今天给大家分享一个浮动效果的自定义控件,首先看图:
CSDN下载 GitHub下载
FloatingMenu控件全部代码:
public class FloatingMenu extends ViewGroup {
// 子菜单和母菜单图标距离
private final static int RADIUS = 250;
// 当前菜单状态
private MenuStatu currentStatu = MenuStatu.STATU_CLOSE;
// 菜单状态枚举
public enum MenuStatu {
STATU_OPEN, STATU_CLOSE
}
/**
* 子菜单被点击回调接口
*/
public interface OnItemMenuClickListener {
void onItemMenuClick(View view, int position);
}
// 子菜单被点击回调接口
private OnItemMenuClickListener onItemMenuClickListener;
public void setOnItemMenuClickListener(OnItemMenuClickListener onItemMenuClickListener) {
this.onItemMenuClickListener = onItemMenuClickListener;
}
public FloatingMenu(Context context) {
super(context);
}
public FloatingMenu(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FloatingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int childCount = getChildCount();
if (childCount < 3)
throw new IllegalStateException("当前控件的孩子控件至少需要3个");
measureChildren(widthMeasureSpec, heightMeasureSpec);
int tempWidth = getChildAt(1).getMeasuredWidth();
int tempHeight = getChildAt(childCount - 1).getMeasuredHeight();
setMeasuredDimension(RADIUS + tempWidth, RADIUS + tempHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int childCount = getChildCount();
// 计算每2个子菜单之间的角度值
float averageAngle = 90 / (childCount - 1 - 1);
for (int i = 0; i < childCount; i++) {
final View childAt = getChildAt(i);
int childWidth = childAt.getMeasuredWidth();
int childHeight = childAt.getMeasuredHeight();
// 第一个子控件是母菜单
if (i == 0) {
int left = measuredWidth - childWidth;
int top = measuredHeight - childHeight;
childAt.layout(left, top, measuredWidth, measuredHeight);
childAt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
changeStatuAnim(300);
}
});
} else { // 其余的为子菜单
final int temp = i;
// 计算每一个子菜单的位置
float calAngle = (i - 1) * averageAngle;
double centerX = RADIUS * Math.cos(Math.PI / 180 * calAngle);
double centerY = RADIUS * Math.sin(Math.PI / 180 * calAngle);
int left = (int) (measuredWidth - centerX - childWidth);
int top = (int) (measuredHeight - centerY - childHeight);
int right = (int) (measuredWidth - centerX);
int bottom = (int) (measuredHeight - centerY);
childAt.layout(left, top, right, bottom);
childAt.setVisibility(View.GONE);
childAt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (onItemMenuClickListener != null) {
onItemMenuClickListener.onItemMenuClick(childAt, temp);
}
clickItemAnim(temp);
}
});
}
}
}
}
/**
* 点击子菜单时的动画效果
*
* @param position
*/
private void clickItemAnim(int position) {
for (int i = 1; i < getChildCount(); i++) {
View childAt = getChildAt(i);
if (i == position) {
childAt.startAnimation(toBig());
} else {
childAt.startAnimation(toSmall());
}
childAt.setVisibility(GONE);
}
changeStatu();
}
/**
* 变小,变透明
*/
private Animation toSmall() {
AnimationSet animationSet = new AnimationSet(true);
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
ScaleAnimation scaleAnimation = new ScaleAnimation(1, 0, 1, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animationSet.setDuration(200);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(scaleAnimation);
return animationSet;
}
/**
* 变大,变透明
*
* @return
*/
private Animation toBig() {
AnimationSet animationSet = new AnimationSet(true);
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
ScaleAnimation scaleAnimation = new ScaleAnimation(1, 3, 1, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animationSet.setDuration(200);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(scaleAnimation);
return animationSet;
}
/**
* 子菜单状态改变动画效果
*
* @param durationMillis 动画执行时间
*/
private void changeStatuAnim(int durationMillis) {
int childCount = getChildCount();
for (int i = 1; i < childCount; i++) {
final View view = getChildAt(i);
float jiao = 90 / (childCount - 1 - 1);
float jiJiao = (i - 1) * jiao;
float toX = (float) (RADIUS * Math.cos(Math.PI / 180 * jiJiao));
float toY = (float) (RADIUS * Math.sin(Math.PI / 180 * jiJiao));
AnimationSet animationSet = new AnimationSet(true);
RotateAnimation rotateAnim = new RotateAnimation(
0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
TranslateAnimation translateAnimation;
AlphaAnimation alphaAnimation;
// 根据子菜单状态实现不同的动画效果
if (!isOpen()) {
translateAnimation = new TranslateAnimation(toX, 0, toY, 0);
alphaAnimation = new AlphaAnimation(0, 1);
} else {
translateAnimation = new TranslateAnimation(0, toX, 0, toY);
alphaAnimation = new AlphaAnimation(1, 0);
}
// 注意先添加旋转动画,再添加平移动画
animationSet.addAnimation(rotateAnim);
animationSet.addAnimation(translateAnimation);
animationSet.addAnimation(alphaAnimation);
animationSet.setDuration(durationMillis);
animationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (currentStatu == MenuStatu.STATU_OPEN) {
view.setVisibility(View.VISIBLE);
} else {
view.setVisibility(View.GONE);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
view.startAnimation(animationSet);
}
changeStatu();
}
/**
* 改变状态
*/
private void changeStatu() {
currentStatu = (currentStatu == MenuStatu.STATU_OPEN) ? MenuStatu.STATU_CLOSE : MenuStatu.STATU_OPEN;
}
/**
* 对外暴露的方法,关闭子菜单
*/
public void closeMenu() {
changeStatuAnim(300);
}
/**
* 判断是否打开子菜单
*
* @return
*/
public boolean isOpen() {
return currentStatu == MenuStatu.STATU_OPEN;
}
}
布局文件
public class MainActivity extends AppCompatActivity {
private ListView listView;
private FloatingMenu floating;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listview);
floating = (FloatingMenu) findViewById(R.id.floating);
initFloatingMenu();
setlistView();
}
/**
* 初始化浮动菜单控件
*/
private void initFloatingMenu() {
floating.setOnItemMenuClickListener(new FloatingMenu.OnItemMenuClickListener() {
@Override
public void onItemMenuClick(View view, int position) {
Toast.makeText(MainActivity.this, "子菜单 - " + position, Toast.LENGTH_SHORT).show();
}
});
}
/**
* 设置ListView中的数据
*/
private void setlistView() {
final List list = new ArrayList<>();
for (int i = 0; i < 40; i++) {
list.add("ListView Item Data - " + i);
}
listView.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, list));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
// 关闭菜单和响应条目事件不同时进行
// 如果需要同时进行就去掉判断语句就行了
// floating.closeMenu();
// Toast.makeText(MainActivity.this, list.get(position) + "", Toast.LENGTH_SHORT).show();
if (floating.isOpen()) {
floating.closeMenu();
} else {
Toast.makeText(MainActivity.this, list.get(position) + "", Toast.LENGTH_SHORT).show();
}
}
});
}
}