android精彩编程案例系列

第4例:卫星菜单

2018-06-27  本文已影响109人  追梦小乐

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

效果图如下

GIF.gif

功能实现过程

1、strings.xml

<resources>
    <string name="app_name">卫星菜单</string>
    <string name="text_btn1">子按钮1</string>
    <string name="text_btn2">子按钮2</string>
    <string name="text_btn3">子按钮3</string>
    <string name="text_btn4">子按钮4</string>
    <string name="text_btn5">子按钮5</string>
</resources>

2、attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!--半径属性-->
    <attr name="radius" format="dimension" />
    <!--自定义控件属性-->
    <declare-styleable name="ArcMenu">
        <!--<attr name="position" />-->
        <attr name="radius" />
    </declare-styleable>

</resources>

3、rotatembutton.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate
        android:fromDegrees="0"
        android:toDegrees="359"
        android:duration="500"
        android:repeatCount="-1"
        android:pivotX="50%"
        android:pivotY="50%" />
</set>

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(引入自定义控件)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:menu="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg"
   >
<com.example.satellitemenu.SatelliteMenu
    android:id="@+id/satelliteMenu"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    menu:radius="100dp">
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/button_bg" >

        <ImageView
            android:id="@+id/id_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/button_in" />

    </RelativeLayout>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/img5"
        android:tag="@string/text_btn1" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/img4"
        android:tag="@string/text_btn2" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/img3"
        android:tag="@string/text_btn3" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/img2"
        android:tag="@string/text_btn4" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/img1"
        android:tag="@string/text_btn5" />
</com.example.satellitemenu.SatelliteMenu>
</RelativeLayout>

上一篇 下一篇

猜你喜欢

热点阅读