美文网首页
XCArcMenuView 控件的使用

XCArcMenuView 控件的使用

作者: geaosu | 来源:发表于2019-08-01 02:06 被阅读0次

    本文涉及内容如下:

    1. XCArcMenuView 控件显示截图展示;
    2. XCArcMenuView 控件源码+自定义属性内容+xml布局+activity/fragment中的使用代码;
    3. XCArcMenuView 控件在使用过程中可能会遇到的问题总结;

    废话不多上, 上图:


    XCArcMenuView 控件显示截图

    动图: 加载中...

    XCArcMenuView.java 类源码
    我顺便新增了打开和关闭的方法, 方法忘记复制过来了, 后期会补齐

    package com.geaosu.app.widget;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.util.TypedValue;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.ViewGroup;
    import android.view.animation.AlphaAnimation;
    import android.view.animation.Animation;
    import android.view.animation.Animation.AnimationListener;
    import android.view.animation.AnimationSet;
    import android.view.animation.RotateAnimation;
    import android.view.animation.ScaleAnimation;
    import android.view.animation.TranslateAnimation;
    
    import com.geaosu.testapplication.R;
    
    /**
     * 卫星式菜单View
     */
    public class XCArcMenuView extends ViewGroup implements OnClickListener {
    
        private static final int POS_LEFT_TOP = 0;
        private static final int POS_LEFT_BOTTOM = 1;
        private static final int POS_RIGHT_TOP = 2;
        private static final int POS_RIGHT_BOTTOM = 3;
    
        //位置
        private Position mPosition = Position.RIGHT_BOTTOM;
        //主icon到item的icon的距离
        private int mRadius;
        //状态
        private Status mStatus = Status.CLOSE;
        //主菜的单按钮
        private View mCButton;
        //事件监听器
        private OnItemClickListener mOnItemClickListener;
    
        /**
         * 菜单的状态枚举类
         */
        public enum Status {
            OPEN,
            CLOSE
        }
    
        /**
         * 菜单的位置枚举类
         */
        public enum Position {
            LEFT_TOP,
            LEFT_BOTTOM,
            RIGHT_TOP,
            RIGHT_BOTTOM
        }
    
    
        /**
         * 从代码中new对象
         *
         * @param context
         */
        public XCArcMenuView(Context context) {
            this(context, null);
            // TODO Auto-generated constructor stub
        }
    
        /**
         * 从代码中new对象, 带有主题的
         *
         * @param context
         * @param attrs
         */
        public XCArcMenuView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
            // TODO Auto-generated constructor stub
        }
    
        /**
         * 从布局中加载对象
         *
         * @param context
         * @param attrs
         * @param defStyle
         */
        public XCArcMenuView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            // TODO Auto-generated constructor stub
            //获取自定义属性
            TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.XCArcMenuView, defStyle, 0);
            //获取布局中设置的位置值(positio的值)
            int pos = typedArray.getInt(R.styleable.XCArcMenuView_position, POS_RIGHT_BOTTOM);
            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) typedArray.getDimension(R.styleable.XCArcMenuView_radius, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, getResources().getDisplayMetrics()));
            Log.v("czm", "mPosition = " + mPosition + ",mRadius = " + mRadius);
            typedArray.recycle();
        }
    
        /**
         * 设置监听器
         */
        public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
            this.mOnItemClickListener = onItemClickListener;
        }
    
    
        /**
         * 绘制
         *
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // TODO Auto-generated method stub
            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) {
            // TODO Auto-generated method stub
            if (changed) {
                layoutCButton();
                layoutMenuItems();
            }
        }
    
    
        /**
         * 布局主菜单的摆放位置
         */
        private void layoutCButton() {
            // TODO Auto-generated method stub
            mCButton = getChildAt(0);
            mCButton.setOnClickListener(this);
            int l = 0;
            int t = 0;
            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;
                default:
                    break;
            }
            mCButton.layout(l, t, l + width, t + height);
        }
    
        /**
         * 布局菜单项
         */
        private void layoutMenuItems() {
            // TODO Auto-generated method stub
            int count = getChildCount();
            for (int i = 0; i < count - 1; i++) {
                View child = getChildAt(i + 1);
                int l = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));
                int t = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));
                int width = child.getMeasuredWidth();
                int height = child.getMeasuredHeight();
    
                // 如果菜单位置在底部 左下,右下
                if (mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM) {
                    t = getMeasuredHeight() - height - t;
                }
                // 右上,右下
                if (mPosition == Position.RIGHT_TOP || mPosition == Position.RIGHT_BOTTOM) {
                    l = getMeasuredWidth() - width - l;
                }
                child.layout(l, t, l + width, t + height);
                child.setVisibility(View.GONE);
            }
        }
    
        /**
         * 主菜单的点击事件
         */
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            mCButton = findViewById(R.id.btn1);
            rotateCButton(v, 0, 360, 300);
            toggleMenu(300);
        }
    
        /**
         * 切换菜单(展开/隐藏 item)
         */
        public void toggleMenu(int duration) {
            // TODO Auto-generated method stub
            // 为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;
    
                if (mStatus == Status.CLOSE) {
                    // to open
                    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 AnimationListener() {
    
                    @Override
                    public void onAnimationStart(Animation animation) {
    
                    }
    
                    @Override
                    public void onAnimationRepeat(Animation animation) {
    
                    }
    
                    @Override
                    public void onAnimationEnd(Animation animation) {
                        if (mStatus == 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 (mOnItemClickListener != null) {
                            mOnItemClickListener.onItemClick(childView, pos);
                        }
                        menuItemAnim(pos - 1);
                        changeStatus();
                    }
                });
            }
            // 切换菜单状态
            changeStatus();
        }
    
        /**
         * 选择主菜单按钮
         */
        private void rotateCButton(View v, float start, float end, int duration) {
            // TODO Auto-generated method stub
            RotateAnimation anim = new RotateAnimation(start, end, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            anim.setDuration(duration);
            anim.setFillAfter(true);
            v.startAnimation(anim);
        }
    
        /**
         * Item的点击隐藏动画
         */
        private void menuItemAnim(int pos) {
            for (int i = 0; i < getChildCount() - 1; i++) {
                View childView = getChildAt(i + 1);
                if (i == pos) {
                    childView.startAnimation(scaleBigAnim(300));
                } else {
                    childView.startAnimation(scaleSmallAnim(300));
                }
    
                //item不可点击
                childView.setClickable(false);
                childView.setFocusable(false);
                //解决无法显示并且无法点击问题
                childView.setVisibility(View.GONE);
            }
        }
    
        /**
         * 为当前点击的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设置变大和透明度降低的动画
         */
        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() {
            mStatus = (mStatus == Status.CLOSE ? Status.OPEN : Status.CLOSE);
        }
    
        /**
         * 判断是否处于展开状态
         *
         * @return
         */
        public boolean isOpen() {
            return mStatus == Status.OPEN;
        }
    
        /**
         * 判断是否处于展开状态
         *
         * @return
         */
        public boolean isShow() {
            return mStatus == Status.OPEN;
        }
    
        /**
         * 打开item
         */
        public void open() {
            if (!isShow()) {
                menuItemAnim(getChildCount());
                changeStatus();
            }
        }
    
        /**
         * 关闭item
         */
        public void close() {
            if (isShow()) {
                menuItemAnim(getChildCount());
                changeStatus();
            }
        }
    
        /**
         * 显示item
         */
        public void show() {
            if (!isShow()) {
                menuItemAnim(getChildCount());
                changeStatus();
            }
        }
    
        /**
         * 隐藏item
         */
        public void hide() {
            if (isShow()) {
                menuItemAnim(getChildCount());
                changeStatus();
            }
        }
    
        /**
         * 点击子菜单项的回调接口
         */
        public interface OnItemClickListener {
            void onItemClick(View view, int pos);
        }
    }
    
    

    在activity或者fragment中使用

     XCArcMenuView view = (XCArcMenuView) findViewById(R.id.arcmenu);
            view.setOnItemClickListener(new XCArcMenuView.OnItemClickListener() {
    
                @Override
                public void onItemClick(View view, int pos) {
                    // TODO Auto-generated method stub
                    String tag = (String) view.getTag();
                    Toast.makeText(MainActivity.this, tag, Toast.LENGTH_SHORT).show();
                }
            });
    

    自定义属性文件: attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="XCArcMenuView">
            <attr name="position">
                <enum name="left_top" value="0" />
                <enum name="left_bottom" value="1" />
                <enum name="right_top" value="2" />
                <enum name="right_bottom" value="3" />
            </attr>
            <attr name="radius" format="dimension" />
        </declare-styleable>
    </resources>
    

    xml布局代码

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.geaosu.testapplication.widget.XCArcMenuView
            android:id="@+id/arcmenu"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentBottom="true"
            app:position="left_bottom"
            app:radius="100dp">
    
            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="#000000">
    
                <ImageView
                    android:id="@+id/btn1"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:layout_centerInParent="true"
                    android:src="@mipmap/bg" />
            </RelativeLayout>
    
            <ImageView
                android:id="@+id/btn2"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:src="@mipmap/bg"
                android:tag="camera" />
    
            <ImageView
                android:id="@+id/btn3"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:src="@mipmap/bg"
                android:tag="music" />
    
            <ImageView
                android:id="@+id/btn4"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:src="@mipmap/bg"
                android:tag="place" />
    
        </com.geaosu.testapplication.widget.XCArcMenuView>
    
        <com.geaosu.testapplication.widget.XCArcMenuView
            android:id="@+id/arcmenu2"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_alignParentRight="true"
            android:layout_alignParentBottom="true"
            app:position="right_bottom"
            app:radius="100dp">
    
            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="#000000">
    
                <ImageView
                    android:id="@+id/btn11"
                    android:layout_width="50dp"
                    android:layout_height="50dp"
                    android:layout_centerInParent="true"
                    android:src="@mipmap/bg" />
            </RelativeLayout>
    
            <ImageView
                android:id="@+id/btn12"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:src="@mipmap/bg"
                android:tag="camera" />
    
            <ImageView
                android:id="@+id/btn13"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:src="@mipmap/bg"
                android:tag="music" />
    
            <ImageView
                android:id="@+id/btn14"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:src="@mipmap/bg"
                android:tag="place" />
    
        </com.geaosu.testapplication.widget.XCArcMenuView>
    </RelativeLayout>
    
    

    在使用过程中可能会遇到的问题总结:

    问题1: 在fragment中使用时无法隐藏和点击问题
    
    缘由: 前几天发现了一个控件显示问题, 最近任务被安排的很满, 一直没时间去改, 直到昨天, 这个任务分给了我, 我昨天任务太多, 所有今天才处理这个问题.
    
    问题描述: 我们的项目里使用了一个开源控件, 该控件博客介绍地址(https://www.jb51.net/article/91158.htm), 这个控件展开没有任何问题, 但是隐藏时会出现问题, 是这样的, 我们在fragment中使用该控件时, 当该控件隐藏后, 来回切换fragment时发现, 该控件显示了出来, 并且item是无法点击的.
    
    解决方案: 我看了源码后发现, 可能是作者的疏忽了, 忘记了一行代码, 就是在执行完隐藏动画后, 设置了animationSet.setFillAfter(true)属性, 让view保持动画结束的状态, 当我们切换fragment的时候, view重新绘制了, 这是这个属性就不起做作用了, 导致所有的item显示了, 并且无法点击是因为作者添加了childView.setClickable(false)这行代码, 禁止掉了view的点击事件, 到这里问题已经可以解决了, 这里只需要加上childView.setVisibility(View.GONE)这行代码即可;
    
    可能有人不知道在哪里加这行代码, 我把整个方法贴出来, 后面还会把这个类以及这个类的使用和布局xml都会贴出来供大家学习借鉴: 
    
    /**
     * Item的点击隐藏动画
     */
    private void menuItemAnim(int pos) {
        for (int i = 0; i < getChildCount() - 1; i++) {
            View childView = getChildAt(i + 1);
            if (i == pos) {
                childView.startAnimation(scaleBigAnim(300));
            } else {
                childView.startAnimation(scaleSmallAnim(300));
            }
            //item不可点击
            childView.setClickable(false);
            childView.setFocusable(false);
            //解决无法显示并且无法点击问题
            childView.setVisibility(View.GONE);
        }
    }
    

    相关文章

      网友评论

          本文标题:XCArcMenuView 控件的使用

          本文链接:https://www.haomeiwen.com/subject/uyrfdctx.html