实现ArcMenu

传承者(Inheritors)打造共同进步生态圈!!!
转载:http://blog.csdn.net/lmj623565791/article/details/37567907

三段论:定义属性,自定义ViewGroup,调用
这里写图片描述

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

</resources>
自定义ViewGroup
public class ArcMenu extends ViewGroup implements View.OnClickListener{
    /**
     *  菜单的显示位置
     */
    private Position mPosition = Position.LEFT_TOP;
    /**
     * 菜单显示的半径,默认100dp
     */
    private int mRadius = 100;
    /**
     * 用户点击的按钮
     */
    private View mButton;
    /**
     * 当前ArcMenu的状态
     */
    private Status mCurrentStatus = Status.CLOSE;
    /**
     * 回调接口
     */
    private OnMenuItemClickListener  onMenuItemClickListener;
    /**
     * 状态的枚举
     */
    public enum Status{
        OPEN,CLOSE
    }
    /**
     * 设置菜单实现的位置,四选一,默认右下
     */
    public  enum Position{
    LEFT_TOP,RIGHT_TOP,RIGHT_BOTTOM,LEFT_BOTTOM
}
    public interface OnMenuItemClickListener{
        void onClick(View view,int pos);
    }

    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, mRadius, getResources().getDisplayMetrics());
        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0);
        int indexCount = typedArray.getIndexCount();
        for (int i = 0; i < indexCount; i++) {
            int attr = typedArray.getIndex(i);
            switch (attr){
                case R.styleable.ArcMenu_position:
                    int val = typedArray.getInt(attr, 0);
                    switch (val){
                        case 0:
                            mPosition = Position.LEFT_TOP;
                            break;
                        case 1:
                            mPosition = Position.RIGHT_TOP;
                            break;
                        case 2:
                            mPosition = Position.RIGHT_BOTTOM;
                            break;
                        case 3:
                            mPosition = Position.LEFT_BOTTOM;
                            break;
                    }
                    break;
                case R.styleable.ArcMenu_radius:
                    mRadius = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100f, getResources().getDisplayMetrics()));

            }

        }
    typedArray.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 为按钮添加点击事件
     * @param v
     */
    @Override
    public void onClick(View v) {
        mButton = findViewById(R.id.id_button);
        if(mButton == null){
            mButton = getChildAt(0);
        }
        rotateView(mButton,0f,270f,300);
        toggleMenu(300);
    }

    private void toggleMenu(int durationMillis) {
    int count = getChildCount();
        for (int i = 0; i < count - 1; i++) {
            final View childView = getChildAt(i + 1);
            childView.setVisibility(VISIBLE);

            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;
            }
            int cl = (int)(mRadius*Math.sin(Math.PI/2/(count - 2)*i));
            int ct = (int)(mRadius*Math.cos(Math.PI/2/(count - 2)*i));

            AnimationSet animationSet = new AnimationSet(true);
            Animation animation = null;
            if(mCurrentStatus == Status.CLOSE){
                //to open
                animationSet.setInterpolator(new OvershootInterpolator(2F));
                animation = new TranslateAnimation(xflag*cl,0,yflag*ct,0);
                childView.setClickable(true);
                childView.setFocusable(true);
            }else{//to close
                animation = new TranslateAnimation(0f,xflag*cl,0f,yflag*ct);
                childView.setFocusable(false);
                childView.setClickable(false);
            }
            animation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                        if(mCurrentStatus == Status.CLOSE){
                            childView.setVisibility(GONE);
                        }
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });


            animation.setFillAfter(true);
            animation.setDuration(durationMillis);

            //为动画设置一个开始延迟时间
            animation.setStartOffset((i*100)/(count - 1));
            RotateAnimation rotate = new RotateAnimation(0,720,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
            rotate.setDuration(durationMillis);
            rotate.setFillAfter(true);

            animationSet.addAnimation(rotate);
            animationSet.addAnimation(animation);
            childView.startAnimation(animationSet);

            final  int index = i+1;
            childView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(onMenuItemClickListener != null){
                        onMenuItemClickListener.onClick(childView, index - 1);
                        menuItemAnim(index -1);
                        changeStatus();
                    }
                }
            });
        }
        changeStatus();
    }

    private void changeStatus() {
        mCurrentStatus = (mCurrentStatus == Status.CLOSE?Status.OPEN : Status.CLOSE);

    }

    /**
     * 开始菜单动画,点击的MenuItem放大消失,其他的缩小消失
     * @param item
     */
    private void menuItemAnim(int item) {
        for (int i = 0; i < getChildCount() - 1; i++) {
            View childView = getChildAt(i+1);
            if(i == item){
                childView.startAnimation(scaleBigAnim(300));
            }else{
                childView.startAnimation(scaleSmallAnim(300));
            }
            childView.setClickable(false);
            childView.setFocusable(false);
        }
    }

    /**
     * 缩小消失
     * @param durationMills
     * @return
     */
    private Animation scaleSmallAnim(int durationMills) {
        Animation anim = new ScaleAnimation(1.0f,0f,1.0f,0f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        anim.setDuration(durationMills);
        anim.setFillAfter(true);
        return anim;
    }

    /**
     * 放大,透明度降低
     * @param durationMills
     * @return
     */
    private Animation scaleBigAnim(int durationMills) {
        AnimationSet animationset = new AnimationSet(true);
        Animation anim = new ScaleAnimation(1.0f,4.0f,1.0f,4.0f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        Animation alphaAnimation = new AlphaAnimation(1,0);

        animationset.addAnimation(anim);
       animationset.addAnimation(alphaAnimation);
        animationset.setDuration(durationMills);
        animationset.setFillAfter(true);
        return animationset;
    }

    /**
     * 按钮的旋转动画
     *
     */
    private void rotateView(View view, float fromDegrees, float toDegrees, int durationMillis) {
        RotateAnimation rotate = new RotateAnimation(fromDegrees,toDegrees, Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
       rotate.setDuration(durationMillis);
        rotate.setFillAfter(true);
        view.startAnimation(rotate);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if(changed){
        layoutButton();
        int count = getChildCount();
        /**
         * 设置所有孩子的位置例如
         * (第一个按钮):左上时,从左到右,
         * 第二个:mRadius(sinθ,cosθ)α= Math.PI/2*(cCount_1)
         * 第三个按钮mRadius(sinα,cosα)
         * 第四个:mRadius(sin2α,cos2α)
         * 第五个:mRadius(sin3α,cos3α)
         */
        for (int i = 0; i <count -1 ; i++) {
            View child =getChildAt(i+1);
            child.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 = child.getMeasuredWidth();
            int cHeight = child.getMeasuredHeight();

            //左下,右下
            if(mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM){
                ct = getMeasuredHeight() - cHeight - ct;
            }
            //右上,右下
            if(mPosition == Position.RIGHT_TOP || mPosition == Position.RIGHT_BOTTOM){
                cl = getMeasuredWidth() - cWidth - cl;
            }
            child.layout(cl,ct,cl+cWidth,ct+cHeight);
        }

    }


    }

    /**
     * 第一个子元素为按钮,为俺就布局且初始化点击事件
     */
    private void layoutButton() {
        View cButton = getChildAt(0);
        cButton.setOnClickListener(this);
        int l= 0;
        int t = 0;
        int width = cButton.getMeasuredWidth();
        int height = cButton.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;

        }
        cButton.layout(l,t,l+width,t+height);
    }



    public Position getmPosition()
    {
        return mPosition;
    }

    public void setmPosition(Position mPosition)
    {
        this.mPosition = mPosition;
    }

    public int getmRadius()
    {
        return mRadius;
    }

    public void setmRadius(int mRadius)
    {
        this.mRadius = mRadius;
    }

    public Status getmCurrentStatus()
    {
        return mCurrentStatus;
    }

    public void setmCurrentStatus(Status mCurrentStatus)
    {
        this.mCurrentStatus = mCurrentStatus;
    }

    public OnMenuItemClickListener getOnMenuItemClickListener()
    {
        return onMenuItemClickListener;
    }

    public void setOnMenuItemClickListener(
            OnMenuItemClickListener onMenuItemClickListener)
    {
        this.onMenuItemClickListener = onMenuItemClickListener;
    }

}
布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:xxl="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"


 >

 <com.example.administrator.testapplication.ArcMenu
     android:id="@+id/id_arcmenu1"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     xxl:position="left_top"
     xxl:radius="130dp"
     >
  <RelativeLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:background="@mipmap/composer_button" >

   <ImageView
       android:id="@+id/id_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerInParent="true"
       android:src="@mipmap/composer_icn_plus" />
  </RelativeLayout>

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_camera"
      android:tag="Camera" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_sun"
      android:tag="Sun" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_place"
      android:tag="Place" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_sleep"
      android:tag="Sleep" />

 </com.example.administrator.testapplication.ArcMenu>

 <com.example.administrator.testapplication.ArcMenu
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     xxl:position="right_bottom"
     xxl:radius="130dp" >

  <RelativeLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:background="@mipmap/composer_button" >

   <ImageView
       android:id="@+id/id_button2"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerInParent="true"
       android:src="@mipmap/composer_icn_plus" />
  </RelativeLayout>

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_camera"
      android:tag="Camera" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_sun"
      android:tag="Sun" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_place"
      android:tag="Place" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_sleep"
      android:tag="Sleep" />
 </com.example.administrator.testapplication.ArcMenu>

 <com.example.administrator.testapplication.ArcMenu
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     xxl:position="left_bottom"
     xxl:radius="130dp" >

  <RelativeLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:background="@mipmap/composer_button" >

   <ImageView
       android:id="@+id/id_button3"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerInParent="true"
       android:src="@mipmap/composer_icn_plus" />
  </RelativeLayout>


  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_sun"
      android:tag="Sun" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_place"
      android:tag="Place" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_sleep"
      android:tag="Sleep" />
 </com.example.administrator.testapplication.ArcMenu>

 <com.example.administrator.testapplication.ArcMenu
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     xxl:position="right_top"
     xxl:radius="130dp" >

  <RelativeLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:background="@mipmap/composer_button" >

   <ImageView
       android:id="@+id/id_button4"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerInParent="true"
       android:src="@mipmap/composer_icn_plus" />
  </RelativeLayout>

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_camera"
      android:tag="Camera" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_sun"
      android:tag="Sun" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_place"
      android:tag="Place" />

  <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:src="@mipmap/composer_sleep"
      android:tag="Sleep" />

 </com.example.administrator.testapplication.ArcMenu>
</RelativeLayout >
调用
public class MainActivity extends Activity {
private ArcMenu mArcMenuLeftTop;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mArcMenuLeftTop = (ArcMenu) findViewById(R.id.id_arcmenu1);

        //添加动态的一个MenuItem
        ImageView people = new ImageView(this);
        people.setImageResource(R.mipmap.composer_with);
        people.setTag("People");
        mArcMenuLeftTop.addView(people);

        mArcMenuLeftTop.setOnMenuItemClickListener(new ArcMenu.OnMenuItemClickListener() {
            @Override
            public void onClick(View view, int pos) {

                 Toast.makeText(MainActivity.this,pos + ":" + view.getTag(), Toast.LENGTH_SHORT).show();


            }
        });

    }
}
思考
  • 对于容器自定义各种view计算初始位置,计算结束位置,在位置之间转换添加相应的动画特效,彰显视觉艺术!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值