Android自定义view---ArcMenu

本篇文章学习鸿洋自定义控价慕课网 https://www.imooc.com/video/6232

 一.自定义属性attr文件自定义属性方法。

 <attr name="position">
        <enum name="left_top" value="0"></enum>
        <enum name="left_bottom" value="1"></enum>
        <enum name="right_bottom" value="3"></enum>
        <enum name="right_top" value="2"></enum>
    </attr>

    <attr name="raidus" format="dimension"></attr>
    <declare-styleable name="ArcMenu">
        <attr name="raidus"></attr>
        <attr name="position"></attr>
    </declare-styleable>

二.具体功能

public class ArcMenu extends ViewGroup implements View.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 String TAG = "ArcMenu";


    public Positon mPosition = Positon.RIGHT_BOTTOM;
    private int mRadius;
    private Status mCurrentState = Status.CLOAST;

    private View mButton;


    private onMenuClickListener onMenuClickListener;


    public enum Positon {
        LEFT_TOP, LEFT_BOTTON, RIGHT_TOP, RIGHT_BOTTOM

    }

    public enum Status {
        OPEN, CLOAST
    }


    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);
        mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics());

        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0);
        mRadius = (int) typedArray.getDimension(R.styleable.ArcMenu_raidus, mRadius);
        int pos = typedArray.getInt(R.styleable.ArcMenu_position, POS_RIGHT_BOTTOM);

        switch (pos) {
            case POS_LEFT_TOP:
                mPosition = Positon.LEFT_TOP;
                break;
            case POS_LEFT_BOTTOM:
                mPosition = Positon.LEFT_BOTTON;
                break;
            case POS_RIGHT_TOP:
                mPosition = Positon.RIGHT_TOP;
                break;
            case POS_RIGHT_BOTTOM:
                mPosition = Positon.RIGHT_BOTTOM;
                break;
        }

        Log.e(TAG, "mRaidus--" + mRadius + "  pos--" + pos);

        typedArray.recycle();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int count = getChildCount();
        for (int i = 0; i < count; i++) {

            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);

        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        if (changed) {
            layoutCButton();


            int count = getChildCount();
            for (int i = 0; i < count - 1; i++) {
                View child = getChildAt(i + 1);

                child.setVisibility(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));

                Log.e(TAG, "mPosition---" + mPosition + "child---" + count + "   cl---" + cl + " ct---" + ct);

                int cWidth = child.getMeasuredWidth();
                int cHeight = child.getMeasuredHeight();


                if (mPosition == Positon.LEFT_TOP) {
                    cl += 0;
                    ct += 0;
                }

                if (mPosition == Positon.LEFT_BOTTON) {
                    ct = getMeasuredHeight() - cHeight - ct - 0;
                    cl += 0;
                }

                if (mPosition == Positon.RIGHT_BOTTOM) {
                    ct = getMeasuredHeight() - cHeight - ct - 0;
                    cl = getMeasuredWidth() - cWidth - cl - 0;
                }

                if (mPosition == Positon.RIGHT_TOP) {
                    cl = getMeasuredWidth() - cWidth - cl - 0;
                    ct += 0;
                }

                child.layout(cl, ct, cl + cWidth, ct + cHeight);


            }

        }
    }

    // 定位主菜单按钮
    private void layoutCButton() {
        mButton = getChildAt(0);
        mButton.setOnClickListener(this);
        int l = 0;
        int t = 0;
        int width = mButton.getMeasuredWidth();
        int height = mButton.getMeasuredHeight();

        switch (mPosition) {
            case LEFT_TOP:
                l = t = 0;
                break;
            case LEFT_BOTTON:
                l = 0;
                t = getMeasuredHeight() - height - 0;
                break;
            case RIGHT_TOP:
                l = getMeasuredWidth() - width - 0;
                t = 0;
                break;
            case RIGHT_BOTTOM:
                l = getMeasuredWidth() - width - 0;
                t = getMeasuredHeight() - height - 0;
                break;

        }

        mButton.layout(l, t, l + width, t + width);
    }


    public interface onMenuClickListener {
        void onClick(View view, int pos);
    }


    public void setOnMenuClickListener(onMenuClickListener onMenuClickListener) {
        this.onMenuClickListener = onMenuClickListener;
    }


    @Override
    public void onClick(View v) {
        rotateBtn(v, 0f, 360f, 300);
        toggleMenu(300);

    }

    private void toggleMenu(int duration) {

        int count = getChildCount();

        for (int i = 0; i < count - 1; i++) {
            final View child = getChildAt(i + 1);
            child.setVisibility(VISIBLE);

            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 == Positon.LEFT_TOP || mPosition == Positon.LEFT_BOTTON) {
                xflag = -1;
            }


            if (mPosition == Positon.RIGHT_TOP || mPosition == Positon.LEFT_TOP) {
                yflag = -1;
            }

            AnimationSet animationSet = new AnimationSet(true);
            Animation tranAnim = null;
            if (mCurrentState == Status.CLOAST) {
                tranAnim = new TranslateAnimation(xflag * cl, 0, yflag * ct, 0);
            } else {
                tranAnim = new TranslateAnimation(0, xflag * cl, 0, yflag * ct);
            }

            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 onAnimationEnd(Animation animation) {
                    if (mCurrentState == Status.CLOAST) {
                        child.setVisibility(GONE);
                    }
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });


            RotateAnimation rotateAnimation = new RotateAnimation(0, 720, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0);
            rotateAnimation.setFillAfter(true);
            rotateAnimation.setDuration(duration);


            animationSet.addAnimation(rotateAnimation);
            animationSet.addAnimation(tranAnim);
            child.startAnimation(animationSet);


            final int pos = i + 1;
            child.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {

                    if (onMenuClickListener != null) {
                        onMenuClickListener.onClick(child, pos);
                    }

                    menuItmeAnim(pos - 1);
                    changeStates();
                }


            });


        }
        changeStates();

    }

    private void menuItmeAnim(int pos) {
        for (int j = 0; j < getChildCount() - 1; j++) {

            View childView = getChildAt(j + 1);
            if (j == pos) {

                childView.startAnimation(scaleBigAnim());
            } else {

                childView.setAnimation(scaleSmallAnim());
            }

        }
    }

    private Animation scaleSmallAnim() {

        AnimationSet animationSet = new AnimationSet(true);
        ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.0f, 1.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        AlphaAnimation alphaAnimation = new AlphaAnimation(1f, 0.0f);
        animationSet.addAnimation(scaleAnimation);
        animationSet.addAnimation(alphaAnimation);
        animationSet.setDuration(300);
        animationSet.setFillAfter(true);
        return animationSet;
    }

    private Animation scaleBigAnim() {
        AnimationSet animationSet = new AnimationSet(true);
        ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 2.0f, 1.0f, 2.0F, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        AlphaAnimation alphaAnimation = new AlphaAnimation(1f, 0);
        animationSet.addAnimation(scaleAnimation);
        animationSet.addAnimation(alphaAnimation);
        animationSet.setDuration(300);
        animationSet.setFillAfter(true);
        return animationSet;
    }


    private void changeStates() {
        if (mCurrentState == Status.CLOAST) {
            mCurrentState = Status.OPEN;
        } else {
            mCurrentState = Status.CLOAST;
        }

        Log.d(TAG, "mCurrentState:" + mCurrentState);
    }

    private void rotateBtn(View v, float start, float end, int duration) {
        Log.d("ArcMenu", "点了");
        RotateAnimation rotateAnimation = new RotateAnimation(start, end, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        rotateAnimation.setDuration(duration);
        rotateAnimation.setFillAfter(true);
        v.startAnimation(rotateAnimation);

    }
}

三.使用控价

MainActivity布局文件中使用,postion具体位置,raduis半径。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Main4Activity">

    <com.tk.myviewproject.view.ArcMenu
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:position="left_top"
        app:raidus="200dp">

        <ImageView
            android:id="@+id/id_button"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@mipmap/ic_launcher"></ImageView>


        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/ic_launcher"
            android:tag="tag1"></ImageView>


        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/ic_launcher"
            android:tag="tag2"></ImageView>

        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/ic_launcher"
            android:tag="tag3"></ImageView>

        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/ic_launcher"
            android:tag="tag4"></ImageView>


    </com.tk.myviewproject.view.ArcMenu>


</RelativeLayout>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值