package com.martin.simpledevelop.view; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; import com.martin.simpledevelop.R; /** * @Description 卫星菜单,自定义控件, * @File ArcMenu.java * @Package com.martin.simpledevelop.view * @Date 2015/7/516:53 * @Author Donghongyu 1358506549@qq.com * @Version v1.0.0 */ public class ArcMenu extends ViewGroup implements View.OnClickListener { private final String TAG = ArcMenu.class.getSimpleName(); //Menu position constant private final int POS_LEFT_TOP = 0; private final int POS_LEFT_BOTTOM = 1; private final int POS_RIGHT_TOP = 2; private final int POS_RIGHT_BOTTOM = 3; //菜单位置 private Position mPosition; //菜单的弹射半径 private int mRadius; //菜单的当前状态 private Status mCurrentStatus = Status.CLOSE; //菜单的主按钮 private View mCButton; //Buttom of the listener private OnMenuItemClickListener mMenuItemClickListener; //Setting the main menu click listener public void setOnMenuItemClickListener(OnMenuItemClickListener mMenuItemClickListener) { this.mMenuItemClickListener = mMenuItemClickListener; } /** * 按钮的选项监听 */ public interface OnMenuItemClickListener { void onClick(View view, int pos); } /** * 菜单的状态 */ private enum Status { OPEN, CLOSE } /** * 卫星菜单的位置 */ private enum Position { RIGHT_TOP, RIGHT_BOTTOM, LEFT_TOP, LEFT_BOTTOM } public ArcMenu(Context context) { this(context, null); } public ArcMenu(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ArcMenu(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //Set the main menu default shoot off radius mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics()); //Get the customer propertys value TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0); //Get the main menu position int pos = array.getInt(R.styleable.ArcMenu_position, POS_RIGHT_TOP); //Check user edit attrs switch (pos) { case POS_LEFT_TOP: mPosition = Position.LEFT_TOP; break; case POS_LEFT_BOTTOM: mPosition = Position.LEFT_BOTTOM; break; case POS_RIGHT_TOP: mPosition = Position.RIGHT_TOP; break; case POS_RIGHT_BOTTOM: mPosition = Position.RIGHT_BOTTOM; break; } mRadius = (int) array.getDimension(R.styleable.ArcMenu_radius, mRadius); //属性回收 array.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //获取控件的内部的子控件的数量 int childCount = getChildCount(); //循环 for (int i = 0; i < childCount; i++) { //测量子控件的大小,多宽,多高, 内部加上了viewGroup的padding值 measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed) { layoutCButton(); layotuItemButton(); } } /** * 初始化子菜单项 */ private void layotuItemButton() { int count = getChildCount(); for (int i = 0; i < count - 1; i++) { View cView = getChildAt(i + 1); cView.setVisibility(View.GONE); //计算子菜单项的位置 int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i)); int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i)); //计算子控件的宽高 int cWidth = cView.getMeasuredWidth(); int cHeight = cView.getMeasuredHeight(); //根据控件的位置进行修改 //如果菜单位置在底部,左下,右下 if (mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM) { ct = getMeasuredHeight() - cHeight - ct; } //如果菜单位置在顶部,左上,右上 if (mPosition == Position.LEFT_TOP || mPosition == Position.RIGHT_BOTTOM) { cl = getMeasuredWidth() - cWidth - cl; } //进行初始化 cView.layout(cl, ct, cl + cWidth, ct + cHeight); } } /** * 定位主菜单按钮 */ private void layoutCButton() { //默认第一个控件就是转牛 mCButton = getChildAt(0); mCButton.setOnClickListener(this); int l = 0;//距左边的位置 int t = 0;//据上边的位置 //r=l+width;b=t+height; //测量控件的宽高 int width = mCButton.getMeasuredWidth(); int height = mCButton.getMeasuredHeight(); //根据布局中的位置属性的值判断按钮的位置 switch (mPosition) { case LEFT_TOP: l = 0; t = 0; break; case LEFT_BOTTOM: l = 0; t = getMeasuredHeight() - height; break; case RIGHT_TOP: l = getMeasuredWidth() - width; t = 0; break; case RIGHT_BOTTOM: l = getMeasuredWidth() - width; t = getMeasuredHeight() - height; break; } mCButton.layout(l, t, l + width, t + height); } @Override public void onClick(View v) { //旋转主按钮 rotateCButton(v, 0f, 360f, 300); toggleMenu(300); } /** * 子菜单的开关的动画设置 * * @param duration */ public void toggleMenu(int duration) { // 为menuItem添加平移动画和旋转动画 int count = getChildCount(); for (int i = 0; i < count - 1; i++) { final View childView = getChildAt(i + 1); childView.setVisibility(View.VISIBLE); // end 0 , 0 // start int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i)); int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i)); int xflag = 1; int yflag = 1; if (mPosition == Position.LEFT_TOP || mPosition == Position.LEFT_BOTTOM) { xflag = -1; } if (mPosition == Position.LEFT_TOP || mPosition == Position.RIGHT_TOP) { yflag = -1; } AnimationSet animset = new AnimationSet(true); Animation tranAnim = null; // to open if (mCurrentStatus == Status.CLOSE) { tranAnim = new TranslateAnimation(xflag * cl, 0, yflag * ct, 0); childView.setClickable(true); childView.setFocusable(true); } else // to close { tranAnim = new TranslateAnimation(0, xflag * cl, 0, yflag * ct); childView.setClickable(false); childView.setFocusable(false); } tranAnim.setFillAfter(true); tranAnim.setDuration(duration); tranAnim.setStartOffset((i * 100) / count); tranAnim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (mCurrentStatus == Status.CLOSE) { childView.setVisibility(View.GONE); } } }); // 旋转动画 RotateAnimation rotateAnim = new RotateAnimation(0, 720, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); rotateAnim.setDuration(duration); rotateAnim.setFillAfter(true); animset.addAnimation(rotateAnim); animset.addAnimation(tranAnim); childView.startAnimation(animset); final int pos = i + 1; childView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mMenuItemClickListener != null) mMenuItemClickListener.onClick(childView, pos); changeStatus(); menuItemAnim(pos - 1); } }); } // 切换菜单状态 changeStatus(); } /** * 添加menuItem点击动画 * * @param pos */ private void menuItemAnim(int pos) { // 为menuItem添加平移动画和旋转动画 int count = getChildCount(); for (int i = 0; i < count - 1; i++) { View childView = getChildAt(i + 1); if (i == pos) { childView.startAnimation(scaleBigAnim(300)); } else { childView.setAnimation(scaleSmallAnim(300)); } childView.setClickable(false); childView.setFocusable(false); // //将按钮位置还原到初始状态 // // end 0 , 0 // // start // int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i)); // int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i)); // // int xflag = 1; // int yflag = 1; // // if (mPosition == Position.LEFT_TOP // || mPosition == Position.LEFT_BOTTOM) // { // xflag = -1; // } // // if (mPosition == Position.LEFT_TOP // || mPosition == Position.RIGHT_TOP) // { // yflag = -1; // } // // AnimationSet animset = new AnimationSet(true); // Animation tranAnim = null; // // tranAnim = new TranslateAnimation(0, xflag * cl, 0, yflag * ct); // childView.setClickable(false); // childView.setFocusable(false); // tranAnim.setFillAfter(true); // tranAnim.setDuration(300); // tranAnim.setStartOffset((i * 100) / count); // animset.addAnimation(tranAnim); // childView.startAnimation(animset); } } /** * 为当前点击的Item设置变小和透明度降低的动画 * * @param duration * @return */ private Animation scaleSmallAnim(int duration) { AnimationSet animationSet = new AnimationSet(true); ScaleAnimation scaleAnim = new ScaleAnimation( 1.0f, 0.0f, 1.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); AlphaAnimation alphaAnim = new AlphaAnimation(1f, 0.0f); animationSet.addAnimation(scaleAnim); animationSet.addAnimation(alphaAnim); animationSet.setDuration(duration); animationSet.setFillAfter(true); return animationSet; } /** * 为当前点击的Item设置变大和透明度降低的动画 * * @param duration * @return */ private Animation scaleBigAnim(int duration) { AnimationSet animationSet = new AnimationSet(true); ScaleAnimation scaleAnim = new ScaleAnimation( 1.0f, 4.0f, 1.0f, 4.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); AlphaAnimation alphaAnim = new AlphaAnimation(1f, 0.0f); animationSet.addAnimation(scaleAnim); animationSet.addAnimation(alphaAnim); animationSet.setDuration(duration); animationSet.setFillAfter(true); return animationSet; } /** * 切换菜单状态 */ private void changeStatus() { mCurrentStatus = (mCurrentStatus == Status.CLOSE ? Status.OPEN : Status.CLOSE); } public boolean isOpen() { return mCurrentStatus == Status.OPEN; } /** * 旋转主按钮的方法, * * @param v 目标控件 * @param start 开始位置 * @param end 结束位置 * @param duradion 持续时间 */ private void rotateCButton(View v, float start, float end, int duradion) { RotateAnimation anim = new RotateAnimation(start, end, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); anim.setDuration(duradion); anim.setFillAfter(true); //控件设置并开始动画 v.startAnimation(anim); } }