第4例:卫星菜单

核心思想知识点:
1)、自定义view的流程

效果图如下

第4例:卫星菜单_第1张图片
GIF.gif

功能实现过程

1、strings.xml


    卫星菜单
    子按钮1
    子按钮2
    子按钮3
    子按钮4
    子按钮5

2、attr.xml




    
    
    
    
        
        
    


3、rotatembutton.xml



    

4、SatelliteMenu .java(自定义控件的核心部分)

public class SatelliteMenu extends ViewGroup {

    private static final String TAG = SatelliteMenu.class.getSimpleName();

    private int pm_width;       //定义屏幕的宽度
    private int pm_height;      //定义屏幕的高度

    //定义菜单半径
    private int mRadius;
    //默认为关闭状态
    private Status mCurrentStatus = Status.CLOSE;
    //触发菜单的按钮
    private View mButton;
    //子菜单单击事件
    private OnSatelliteMenuItemClickListener mMenuItemClickListener;
    //枚举类 菜单状态
    public enum Status
    {
        OPEN, CLOSE
    }
    /**
     * 单击子菜单的回调接口
     */
    public interface OnSatelliteMenuItemClickListener
    {
        void onClick(View view, int pos);
    }

    //构造方法
    public SatelliteMenu(Context context) {
        this(context,null);
    }

    public SatelliteMenu(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public SatelliteMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //        获取屏幕宽高
        WindowManager wm = (WindowManager) getContext()
                .getSystemService(Context.WINDOW_SERVICE);
        pm_width = wm.getDefaultDisplay().getWidth();
        pm_height = wm.getDefaultDisplay().getHeight();

        // 获取自定义属性的值
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
                R.styleable.ArcMenu, defStyleAttr, 0);
        //获取按钮半径属性值
        mRadius = (int) a.getDimension(R.styleable.ArcMenu_radius, TypedValue
                .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100,
                        getResources().getDisplayMetrics()));
        Log.i(TAG,"mRadius============="+mRadius);

        a.recycle();        //回收资源
    }
    /**
     *测量自定义控件中所有子控件的尺寸
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int count = getChildCount();        //获取所有的按钮
        for (int i = 0; i < count; i++)    //遍历所有的按钮
        {
            //测量所有按钮,宽度与高度
            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) {                                    //如果按钮布局发生改变
            buttonLayout();                               //调用主按钮布局位置的方法
            childLayout();

            }
        }

    private void childLayout() {
        int count = getChildCount();                  //获取所有的子按钮
        for (int i = 0; i < count - 1; i++) {         //便利所有按钮
            View child = getChildAt(i + 1);            //获取子控件下标
            child.setVisibility(View.GONE);           //隐藏子按钮

            //获取子按钮的宽高尺寸
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            //==================中=================
            //           中心坐标(pm_width/2-childWidth/2,getMeasuredHeight() - height)
            int c_x = pm_width / 2 - childWidth / 2;
            int c_y = getMeasuredHeight() - childHeight/2;

            //子按钮与父容器左边距
//            Math.sin:返回指定double类型参数的正弦值
            int childLeft = (int) (mRadius * Math.sin(Math.PI / (count - 2)
                    * i));
            int childTop = (int) (mRadius * Math.sin(Math.PI / (count - 2)
                    * i));
            childTop = getMeasuredHeight() - childHeight - childTop;
            if (i == 0) {
                childLeft = c_x - mRadius;
                childTop = getMeasuredHeight() - childHeight;
            } else if (i == 1) {
                childLeft = c_x  - childLeft;
            } else if (i == 2) {
                childLeft = c_x;
                childTop=getMeasuredHeight() - childHeight-mRadius;
            } else if (i == 3) {
                childLeft = c_x  + childLeft;

            } else if (i == 4) {
                childLeft = c_x + mRadius;
                childTop = getMeasuredHeight() - childHeight;
            }
            //设置子按钮的位置
            child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
        }
    }


    /**
     *收缩子按钮动画
     */
    public void shrinkMenu(int time) {
        int count = getChildCount();                    //获取所有的子按钮
        for (int i = 0; i < count - 1; i++)             //便利所有按钮
        {
            final View childView = getChildAt(i + 1);   //获取子按钮下标
            childView.setVisibility(View.VISIBLE);      //显示子按钮
            //==================中=================
                //动画开始与结束的位置x,y
             int clx = (int) (mRadius * Math.sin(Math.PI / (count - 2) * i));
             int cty = (int) (mRadius * Math.cos(Math.PI  / (count - 2) * i));
                if (i == 0) {       //第一个子按钮
                    clx = mRadius;
                    cty = 0;
                } else if (i == 1) {    //第二个子按钮

                } else if (i == 2) {    //第三个子按钮
                    clx = 0;
                    cty = mRadius;
                } else if (i == 3) {    //第四个子按钮
                    clx=(int) (mRadius * Math.cos(Math.PI  / (count - 2) * i));
                    cty=-cty;
                } else if (i == 4) {    //第五个子按钮
                    clx = - mRadius;
                    cty = 0;
                }

            //设置动画集合
            AnimationSet animset = new AnimationSet(true);
            Animation tranAnim = null;

            //如果当前按钮菜单为关闭状态
            if (mCurrentStatus == Status.CLOSE)
            {   //设置打开按钮菜单动画
                tranAnim = new TranslateAnimation(clx,0 , cty, 0);
                childView.setClickable(true);       //子按钮可以单击
                childView.setFocusable(true);       //子按钮可调焦
            } else//如果当前按钮菜单为开启状态
            {   //设置关闭按钮菜单动画
                tranAnim = new TranslateAnimation(0, clx, 0, cty);
                childView.setClickable(false);      //子按钮不可点击
                childView.setFocusable(false);      //子按钮不可调焦
            }
            tranAnim.setDuration(time);             //  动画显示的时间
            tranAnim.setFillAfter(true);            //停止最后一帧的位置
            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(time);       //设置旋转的时间
            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);
                    childButtonClickAnim(pos - 1);      //调用字按钮单击动画方法
                    menuStatus();                       //调用菜单状态方法
                }
            });
        }
        // 切换菜单状态
        menuStatus();

    }

    /**
     * 子按钮单击动画的方法
     */
    private void childButtonClickAnim(int pos) {
        for (int i = 0; i < getChildCount() - 1; i++)
        {

            View childView = getChildAt(i + 1);
            if (i == pos)       //当前单击的子按钮
            {   //启动子按钮变大并消失动画
                childView.startAnimation(scaleBigAnim(200));
            } else
            {
                //启动其它没有被单击的按钮变小并消失动画
                childView.startAnimation(scaleSmallAnim(200));
            }

            childView.setClickable(false);  //子按钮不可点击
            childView.setFocusable(false);  //子按钮不可调焦

        }
    }

    /**
     *没有被单击的子按钮,变小并消失的动画方法
     */
    private Animation scaleSmallAnim(int time)
    {   //设置动画集合
        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(time);         //设置动画时间
        animationSet.setFillAfter(true);        //停止最后一帧的位置
        return animationSet;

    }

    /**
     * 单击子按钮,当前子按钮变大并消失动画方法
     */
    private Animation scaleBigAnim(int time)
    {   //设置动画集合
        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(time);         //设置动画时间
        animationSet.setFillAfter(true);        //停止最后一帧的位置
        return animationSet;

    }

    /**
     * 切换菜单状态
     */
    private void menuStatus()
    {
        mCurrentStatus = (mCurrentStatus == Status.CLOSE ? Status.OPEN
                : Status.CLOSE);
    }
    /**
     *设置主按钮旋转动画
     */
    private void rotatemButton(View v, float start, float end, int time) {
        //中心旋转动画
        RotateAnimation anim = new RotateAnimation(start, end,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        anim.setDuration(time);         //设置旋转的时间
        anim.setFillAfter(true);        //停止最后一帧的位置
        v.startAnimation(anim);         //开始动画
    }

    /**
     * 设置主按钮在布局中的位置
     */
    private void buttonLayout() {
        mButton = getChildAt(0);       //获取菜单主按钮
        //设置按钮的单击事件
        mButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                rotatemButton(v, 0f, 360f, 500);    //调用主按钮旋转的方法
                shrinkMenu(500);                    //调用收缩子按钮动画方法
            }
        });
        //初始化按钮左边距与上边距
        int l = 0;
        int t = 0;
        //获取主按钮的宽度与高度
        int width = mButton.getMeasuredWidth();
        int height = mButton.getMeasuredHeight();
        //判断主按钮位置
            //==================中=================
                l = pm_width/2-width/2;
                t = getMeasuredHeight() - height;
        mButton.layout(l, t, l + width, t + width);  //设置主按钮在父容器的位置
    }
}

5、activity_main.xml(引入自定义控件)




    

        

    

    

    

    

    

    



你可能感兴趣的:(第4例:卫星菜单)