精华内容
下载资源
问答
  • ArcMenu

    2021-03-16 14:21:34
    ArcMenu介绍: 实现弹出式按钮群(菜单)。点击主按钮,会在住按钮旁边弹出多个按钮(菜单)。弹出的按钮有两种排列形式,一种是围绕着主按钮成圆弧形排列(如图1),一种是和主按钮并排成一字型排列(如图2)。
  • Floating-ArcMenu, 所有应用程序的prety菜单 浮动 arcmenu为所有应用程序 prety菜单中新特性的特性向ArcMenu和FloatActionButton添加了SnackBar向上/向下事件( 通过使用CoordinatorLayout作为父级)以编程
  • 自定义ArcMenu

    2015-09-23 18:24:08
    一个自定义的卫星菜单,位置可控,动画可控
  • 您可以在此处查看为什么完整的原因#358(关闭) 亲切的问候LinxGem33又名Andy C 项目信息 介绍 Arc Menu是Gnome Shell扩展,旨在... 要安装最新的官方版本:在GNOME官方扩展网站上访问ArcMenu。 要从源代码安装开
  • ArcMenu(底部)

    2016-03-22 11:59:04
    实现位于底部的Arcmen
  • 本文介绍利用ObjectAnimator简单地实现ArcMenu,直接使用本文的ArcMenu类即可快捷地实现菜单功能。  最终使用效果: 先看下最终的使用效果: private int[] imageRes = {R.id.img_menu, R.id.img_menu1, R.id....
  • android ArcMenu

    2013-12-31 16:02:58
    ArcMenu是一个类似于ISO版Path2.0菜单的Android自定义视图项
  • script type = "text/javascript" src = "arcMenu.js" > < / script > < a xss=removed xss=removed xss=removed> click me < / a > < a xss=removed xss=removed> 1 < / a > ...
  • 实现ArcMenu

    2016-06-15 15:47:54
    TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyleAttr, 0 ); int indexCount = typedArray.getIndexCount(); for ( int i = 0 ; i ; i++) { ...

    传承者(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计算初始位置,计算结束位置,在位置之间转换添加相应的动画特效,彰显视觉艺术!
    展开全文
  • ArcMenu.zip

    2019-07-10 12:10:51
    ArcMenu介绍: 实现弹出式按钮群(菜单)。点击主按钮,会在住按钮旁边弹出多个按钮(菜单)。弹出的按钮有两种排列形式,一种是围绕着主按钮成圆弧形排列(如图1),一种是和主按钮并排成一字型排列(如图2)。 ...
  • 为ubuntu-gnome桌面添加ArcMenu插件 这个插件ArcMenu,可以为ubuntu增加类似于windows开始菜单一样的功能。 安装这个控件,需要按照以下步骤操作: 确保系统已经安装gnome-shell-extensions。如果没有安装,请...

    为ubuntu-gnome桌面添加ArcMenu插件

    这个插件ArcMenu,可以为ubuntu增加类似于windows开始菜单一样的功能。

    ArcMenu控件示意图


    安装这个控件,需要按照以下步骤操作:

    1. 确保系统已经安装gnome-shell-extensions。如果没有安装,请执行apt install gnome-shell-extensions安装。

    2. 在firefox或者chrome中安装Gnome shell integration插件,如下图所示:
      Gnome shell integration浏览器插件

    3. 进入gnome插件管理主页,找到该插件并安装。
      GNOME插件配置主页

    4. 激活(安装)该插件并进行配置。
      ArcMenu插件主页

    5. 安装完成后也可以进行二次配置(在tweak应用中)。
      在这里插入图片描述
      在这里插入图片描述
      关于该插件的具体配置,请参考配置选项

    展开全文
  • MrFu-ArcMenu

    2014-09-03 17:35:23
    ArcMenu menu = (ArcMenu) findViewById(R.id.arc_menu); final int itemCount = ITEM_DRAWABLES.length; for (int i = 0; i ; i++) { ImageView item = new ImageView(this); item.setImageResource(ITEM_...
  • ArcMenu和RayMenu ArcMenu 类似于 (适用于iOS)中的菜单的android自定义视图。 光线菜单 关于 (适用于iOS)的用户体验非常棒,但android版本却错过了很多。 只是为了好玩,我尝试实现Android的惊人菜单,该菜单...
  • Android 实现三种菜单效果,扇形菜单、线性菜单、圆形转盘菜单
  • Github上找到的一个超赞的Menu开源控件,适用于安卓开发,顾名思义,就是一个弧形的菜单控件,淘宝客户端就用了这个控件。内附详细demo
  • 安卓Android源码——ArcMenu.rar
  • 49.[开源][安卓][奇妙的弹出菜单]ArcMenu-master
  • ArcMenu扇形菜单(底部)

    2016-03-22 11:54:17
    参照鸿洋大神的Android 自定义ViewGroup手把手教你实现ArcMenu 然后自己写了一个位于底部的ArcMenu,功能上和效果上都以实现!主要思路:1.计算出中心菜单的位置和其他子菜单的位置2.设置中心菜单的点击事件(动画)3....

    参照鸿洋大神的Android 自定义ViewGroup手把手教你实现ArcMenu
    然后自己写了一个位于底部的ArcMenu,功能上和效果上都以实现!

    主要思路:

    1.计算出中心菜单的位置和其他子菜单的位置
    2.设置中心菜单的点击事件(动画)
    3.设置子菜单的点击监听和动画效果!

    这里写图片描述

    1)计算中心菜单的位置

    if (i == 0) {// 中心菜单
        centerChildHeight = mHeight - child.getMeasuredHeight() / 2;
        // 中间view的中心坐标y
        centerChildWidth = mWidth / 2;
        // 中间view的中心坐标y
    
        child.layout((mWidth - childWidth) / 2, mHeight - childHeight, (mWidth + childWidth) / 2, mHeight);
        child.setOnClickListener(this);

    中心菜单的中心位置的x坐标为,view的宽度的一半
    中心菜单的中心位置的y坐标为,view的高度减去一半中心菜单自身高度的
    所以中心菜单的左上右下坐标位置就可以算出来了!

    2)计算子菜单的位置

    child.setVisibility(View.GONE);
    double temA = Math.PI / (childCount - 2) * (i - 1);
    int left = 0;
    int top = 0;
    int right = 0;
    int bottom = 0;
    left = (int) (centerChildWidth + radius * Math.cos(temA) - childWidth / 2);
    top = (int) (centerChildHeight - radius * Math.sin(temA) - childHeight / 2);
    right = (int) (centerChildWidth + radius * Math.cos(temA) + childWidth / 2);
    bottom = (int) (centerChildHeight - radius * Math.sin(temA) + childHeight / 2);
    child.layout(left, top, right, bottom);

    其他子菜单的位置的计算分两步:
    1.根据中心坐标的中心点位置根据弧度/sin/cos分别计算出其他子菜单的中心点位置
    2.根据计算所得的中心点坐标再根据子菜单自身的宽高计算出子菜单的左上右下坐标

    位置计算好了基本上相当于ArcMenu完成了一大部分,其他的部分就是设置动画效果了

    下面贴出来全部的代码

    package com.example.arcmenu;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.provider.AlarmClock;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;
    import android.widget.RelativeLayout;
    import android.view.View.OnClickListener;
    import android.view.animation.AlphaAnimation;
    import android.view.animation.Animation;
    import android.view.animation.AnimationSet;
    import android.view.animation.OvershootInterpolator;
    import android.view.animation.RotateAnimation;
    import android.view.animation.ScaleAnimation;
    import android.view.animation.TranslateAnimation;
    
    public class ArcMenuGroup extends RelativeLayout implements OnClickListener {
    
        private static String TAG = "ArcMenuGroup";
        private int position = 1;// 标识菜单的位置 0:上 1:下(当前代码未使用,仅开发了下方的菜单)
        private int radius = dip2px(getContext(), 100);// 菜单的半径
        private int mHeight;
        private int mWidth;
        private int centerChildHeight;
        private int centerChildWidth;
        private View mMenu;
        private boolean mStatus = false;// true表示打开,false表示关闭
        private OnItemClicklistener mOnItemClickListener;
        private int childCount;
        private AnimationSet mItemAnimationSet;//菜单项被点击的动画集合
    
        public ArcMenuGroup(Context context) {
            this(context, null);
        }
    
        public ArcMenuGroup(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public ArcMenuGroup(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyle, 0);
            int count = array.getIndexCount();
            for (int i = 0; i < count; i++) {
                int index = array.getIndex(i);
                switch (index) {
                case R.styleable.ArcMenu_position:
                    position = array.getInteger(index, 1);
                    break;
                case R.styleable.ArcMenu_radius:
                    radius = (int) array.getDimension(index, dip2px(context, 100));
                default:
                    break;
                }
            }
    
            array.recycle();
    
            /**
             * 完成菜单项被点击的动画的初始化
             */
            mItemAnimationSet = new AnimationSet(false);//false标识动画集中的动画各自使用自己的动画插入器
    
            //创建一个形变动画,从相对于自身中心点由1倍体积扩大到3倍体积
            ScaleAnimation mScaleAnimation = new ScaleAnimation(1.0f, 3.0f, 1.0f, 3.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            mScaleAnimation.setDuration(400);
            //创建一个透明度动画,透明度从不透明到完全透明
            AlphaAnimation mAlphaAnimation = new AlphaAnimation(1.0f, 0.0f);
            mAlphaAnimation.setDuration(400);
            mItemAnimationSet.addAnimation(mAlphaAnimation);
            mItemAnimationSet.addAnimation(mScaleAnimation);
    
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            measureChildren(widthMeasureSpec, heightMeasureSpec);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            mHeight = getMeasuredHeight();
            mWidth = getMeasuredWidth();
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            if (changed) {
                childCount = getChildCount();
                if (childCount <= 2) {//菜单项不能少于两个
                    return;
                }
                for (int i = 0; i < childCount; i++) {
                    View child = getChildAt(i);
                    int childHeight = child.getMeasuredHeight();
                    int childWidth = child.getMeasuredWidth();
                    if (i == 0) {// 中心菜单
                        centerChildHeight = mHeight - child.getMeasuredHeight() / 2;// 中间view的中心坐标y
                        centerChildWidth = mWidth / 2;// 中间view的中心坐标y
    
                        child.layout((mWidth - childWidth) / 2, mHeight - childHeight, (mWidth + childWidth) / 2, mHeight);
                        child.setOnClickListener(this);
                    } else {//根据弧度计算出每个子菜单的位置
                        child.setVisibility(View.GONE);
                        double temA = Math.PI / (childCount - 2) * (i - 1);
                        int left = 0;
                        int top = 0;
                        int right = 0;
                        int bottom = 0;
                        left = (int) (centerChildWidth + radius * Math.cos(temA) - childWidth / 2);
                        top = (int) (centerChildHeight - radius * Math.sin(temA) - childHeight / 2);
                        right = (int) (centerChildWidth + radius * Math.cos(temA) + childWidth / 2);
                        bottom = (int) (centerChildHeight - radius * Math.sin(temA) + childHeight / 2);
                        child.layout(left, top, right, bottom);
                        Log.e(TAG, "i=" + i + " left = " + left + " top = " + top + " right = " + right + " bottom = " + bottom);
                    }
                }
            }
        }
    
        @Override
        public void onClick(View v) {
            startCenterMenuAnimation();
            startItemMenuAnimation();
            changeStatus();
        }
    
        /**
         * 设置子菜单展开和收回的动画
         */
        private void startItemMenuAnimation() {
            final int childCount = getChildCount();
            TranslateAnimation animation = null;
            for (int i = 1; i < childCount; i++) {
                final int position = i;
                double temA = Math.PI / (childCount - 2) * (i - 1);
                final View child = getChildAt(i);
                if (mStatus) {
                    animation = new TranslateAnimation(0, -(float) (radius * Math.cos(temA)), 0, (float) (radius * Math.sin(temA)));
                    child.setVisibility(View.GONE);
                    animation.setDuration(300);
                } else {
    
                    animation = new TranslateAnimation(-(float) (radius * Math.cos(temA)), 0, (float) (radius * Math.sin(temA)), 0);
                    animation.setInterpolator(new OvershootInterpolator(3f));
                    child.setVisibility(View.VISIBLE);
                    animation.setDuration(500);
                }
                child.startAnimation(animation);
                child.setOnClickListener(new OnClickListener() {
    
                    @Override
                    public void onClick(View v) {
                        startItemClickAnimation(position);
                        changeStatus(false);
                        if (mOnItemClickListener != null) {
                            mOnItemClickListener.onClick(child, position);
                        }
                    }
                });
            }
        }
    
        /**
         * 中间主菜单项的动画效果
         */
        private void startCenterMenuAnimation() {
            mMenu = getChildAt(0);
            RotateAnimation animation = new RotateAnimation(0f, 360F, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            animation.setFillAfter(true);
            animation.setDuration(500);
            mMenu.startAnimation(animation);
        }
    
        /**
         * 改变菜单的状态
         */
        private void changeStatus() {
            if (mStatus) {
                mStatus = false;
            } else {
                mStatus = true;
            }
        }
    
        /**
         * 改变菜单的状态
         */
        private void changeStatus(boolean b) {
            mStatus = b;
        }
    
        /**
         * 设置菜单项被点击的动画
         */
        private void startItemClickAnimation(int positon) {
            for (int i = 1; i < childCount; i++) {
                View child = getChildAt(i);
                if (i == positon) {
                    child.startAnimation(mItemAnimationSet);
                }
                child.setVisibility(View.GONE);
            }
        }
    
    
        /**
         *菜单项的监听 
         */
        public interface OnItemClicklistener {
            void onClick(View v, int position);
        }
    
        public OnItemClicklistener getOnItemClickListener() {
            return mOnItemClickListener;
        }
    
        public void setOnItemClickListener(OnItemClicklistener mOnItemClickListener) {
            this.mOnItemClickListener = mOnItemClickListener;
        }
    
        /**
         * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
         */
        public static int dip2px(Context context, float dpValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dpValue * scale + 0.5f);
        }
    
        /**
         * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
         */
        public static int px2dip(Context context, float pxValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (pxValue / scale + 0.5f);
        }
    
    }
    

    下载源码点击这里

    展开全文
  • Android 自定义ViewGroup手把手教你实现ArcMenu

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37567907

    逛eoe发现这样的UI效果,感觉很不错,后来知道github上有这么个开源项目~~~~当然本篇不是教你如何使用这个开源项目,而是教你如何自己通过自定义ViewGroup写这样的效果,自定义ViewGroup也是我的痛楚,嘿嘿,希望以此可以抛砖引玉~~

    效果图:



    1、实现思路

    通过效果图,会有几个问题:

    a、动画效果如何实现

    可以看出动画是从顶点外外发射的,可能有人说,那还不简单,默认元素都在定点位置,然后TraslateAnimation就好了;这样忽略了一点,就是TraslateAnimation虽然有动画效果,但是本质是不会改变按钮的位置,我们的按钮动画结束是要点击的;有人可能会说那使用属性动画,或者改变leftMagin,rightMagin;这样可能比较麻烦,其实我们可以默认让子菜单就已经在目标位置,然后GONE,当点击时还是用TraslateAnimation,把起始位置设为定点,终点位置就是我们隐藏的区域,动画结束VISIBLE.

    b、如何确定位置呢?

    这可能需要一点数学上的知识,我画了一张草图(冰天雪地,跪玻璃碴子求画下面这些图的工具):


    每次会根据子菜单数量,算出a这个角度,然后通过sin , cos 分别算出每个子菜单的left , top ;

    当然这是在左上的情况,如果在右上,则top还是和左上一致的,left则为 (屏幕宽度-左上算出的left) ;其他两个方位同理~


    整体我通过自定义一个ViewGroup,这个ViewGroup中第一个子元素为点击的按钮(你可以随便布局,随便用什么控件),接下来的子元素我认为是菜单项。根据效果图,决定展开半径和显示的位置,让用户自己去定制。下面看具体实现:

    2、自定义View的属性:

    1. <?xml version=“1.0” encoding=“utf-8”?>  
    2. <resources>  
    3.     <attr name=“position”>  
    4.         <enum name=“left_top” value=“0” />  
    5.         <enum name=“right_top” value=“1” />  
    6.         <enum name=“right_bottom” value=“2” />  
    7.         <enum name=“left_bottom” value=“3” />  
    8.     </attr>  
    9.     <attr name=“radius” format=“dimension”></attr>  
    10.   
    11.     <declare-styleable name=“ArcMenu”>  
    12.         <attr name=“position” />  
    13.         <attr name=“radius”/>  
    14.     </declare-styleable>  
    15.   
    16. </resources>  
    <?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"></attr>
    
        <declare-styleable name="ArcMenu">
            <attr name="position" />
            <attr name="radius"/>
        </declare-styleable>
    
    </resources>

    3、在自定义的ViewGroup中获取这些属性

    Arcmenu.Java

    1. /** 
    2.  * @author zhy 
    3.  */  
    4. public class ArcMenu extends ViewGroup implements OnClickListener  
    5. {  
    6.   
    7.     private static final String TAG = “ArcMenu”;  
    8.     /** 
    9.      * 菜单的显示位置 
    10.      */  
    11.     private Position mPosition = Position.LEFT_TOP;  
    12.   
    13.     /** 
    14.      * 菜单显示的半径,默认100dp 
    15.      */  
    16.     private int mRadius = 100;  
    17.     /** 
    18.      * 用户点击的按钮 
    19.      */  
    20.     private View mButton;  
    21.     /** 
    22.      * 当前ArcMenu的状态 
    23.      */  
    24.     private Status mCurrentStatus = Status.CLOSE;  
    25.     /** 
    26.      * 回调接口 
    27.      */  
    28.     private OnMenuItemClickListener onMenuItemClickListener;  
    29.   
    30.     /** 
    31.      * 状态的枚举类 
    32.      *  
    33.      * @author zhy 
    34.      *  
    35.      */  
    36.     public enum Status  
    37.     {  
    38.         OPEN, CLOSE  
    39.     }  
    40.   
    41.     /** 
    42.      * 设置菜单现实的位置,四选1,默认右下 
    43.      *  
    44.      * @author zhy 
    45.      */  
    46.     public enum Position  
    47.     {  
    48.         LEFT_TOP, RIGHT_TOP, RIGHT_BOTTOM, LEFT_BOTTOM;  
    49.     }  
    50.   
    51.     public interface OnMenuItemClickListener  
    52.     {  
    53.         void onClick(View view, int pos);  
    54.     }  
    55.   
    56.     public ArcMenu(Context context)  
    57.     {  
    58.         this(context, null);  
    59.     }  
    60.   
    61.     public ArcMenu(Context context, AttributeSet attrs)  
    62.     {  
    63.         this(context, attrs, 0);  
    64.   
    65.     }  
    66.   
    67.     /** 
    68.      * 初始化属性 
    69.      *  
    70.      * @param context 
    71.      * @param attrs 
    72.      * @param defStyle 
    73.      */  
    74.     public ArcMenu(Context context, AttributeSet attrs, int defStyle)  
    75.     {  
    76.   
    77.         super(context, attrs, defStyle);  
    78.         // dp convert to px  
    79.         mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,  
    80.                 mRadius, getResources().getDisplayMetrics());  
    81.         TypedArray a = context.getTheme().obtainStyledAttributes(attrs,  
    82.                 R.styleable.ArcMenu, defStyle, 0);  
    83.   
    84.         int n = a.getIndexCount();  
    85.         for (int i = 0; i < n; i++)  
    86.         {  
    87.             int attr = a.getIndex(i);  
    88.             switch (attr)  
    89.             {  
    90.             case R.styleable.ArcMenu_position:  
    91.                 int val = a.getInt(attr, 0);  
    92.                 switch (val)  
    93.                 {  
    94.                 case 0:  
    95.                     mPosition = Position.LEFT_TOP;  
    96.                     break;  
    97.                 case 1:  
    98.                     mPosition = Position.RIGHT_TOP;  
    99.                     break;  
    100.                 case 2:  
    101.                     mPosition = Position.RIGHT_BOTTOM;  
    102.                     break;  
    103.                 case 3:  
    104.                     mPosition = Position.LEFT_BOTTOM;  
    105.                     break;  
    106.                 }  
    107.                 break;  
    108.             case R.styleable.ArcMenu_radius:  
    109.                 // dp convert to px  
    110.                 mRadius = a.getDimensionPixelSize(attr, (int) TypedValue  
    111.                         .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100f,  
    112.                                 getResources().getDisplayMetrics()));  
    113.                 break;  
    114.   
    115.             }  
    116.         }  
    117.         a.recycle();  
    118.     }  
    /**
     * @author zhy
     */
    public class ArcMenu extends ViewGroup implements OnClickListener
    {
    
        private static final String TAG = "ArcMenu";
        /**
         * 菜单的显示位置
         */
        private Position mPosition = Position.LEFT_TOP;
    
        /**
         * 菜单显示的半径,默认100dp
         */
        private int mRadius = 100;
        /**
         * 用户点击的按钮
         */
        private View mButton;
        /**
         * 当前ArcMenu的状态
         */
        private Status mCurrentStatus = Status.CLOSE;
        /**
         * 回调接口
         */
        private OnMenuItemClickListener onMenuItemClickListener;
    
        /**
         * 状态的枚举类
         * 
         * @author zhy
         * 
         */
        public enum Status
        {
            OPEN, CLOSE
        }
    
        /**
         * 设置菜单现实的位置,四选1,默认右下
         * 
         * @author zhy
         */
        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);
    
        }
    
        /**
         * 初始化属性
         * 
         * @param context
         * @param attrs
         * @param defStyle
         */
        public ArcMenu(Context context, AttributeSet attrs, int defStyle)
        {
    
            super(context, attrs, defStyle);
            // dp convert to px
            mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                    mRadius, getResources().getDisplayMetrics());
            TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
                    R.styleable.ArcMenu, defStyle, 0);
    
            int n = a.getIndexCount();
            for (int i = 0; i < n; i++)
            {
                int attr = a.getIndex(i);
                switch (attr)
                {
                case R.styleable.ArcMenu_position:
                    int val = a.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:
                    // dp convert to px
                    mRadius = a.getDimensionPixelSize(attr, (int) TypedValue
                            .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100f,
                                    getResources().getDisplayMetrics()));
                    break;
    
                }
            }
            a.recycle();
        }
    

    4、计算子元素的大小:

    1. @Override  
    2.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
    3.     {  
    4.         int count = getChildCount();  
    5.         for (int i = 0; i < count; i++)  
    6.         {  
    7.             // mesure child  
    8.             getChildAt(i).measure(MeasureSpec.UNSPECIFIED,  
    9.                     MeasureSpec.UNSPECIFIED);  
    10.         }  
    11.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
    12.     }  
    @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            int count = getChildCount();
            for (int i = 0; i < count; i++)
            {
                // mesure child
                getChildAt(i).measure(MeasureSpec.UNSPECIFIED,
                        MeasureSpec.UNSPECIFIED);
            }
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }

    5、确定子元素的位置:

    1. @Override  
    2.     protected void onLayout(boolean changed, int l, int t, int r, int b)  
    3.     {  
    4.         if (changed)  
    5.         {  
    6.   
    7.             layoutButton();  
    8.             int count = getChildCount();  
    9.             /** 
    10.              * 设置所有孩子的位置 例如(第一个为按钮): 左上时,从左到右 ] 第2个:mRadius(sin0 , cos0) 
    11.              * 第3个:mRadius(sina ,cosa) 注:[a = Math.PI / 2 * (cCount - 1)] 
    12.              * 第4个:mRadius(sin2a ,cos2a) 第5个:mRadius(sin3a , cos3a) … 
    13.              */  
    14.             for (int i = 0; i < count - 1; i++)  
    15.             {  
    16.                 View child = getChildAt(i + 1);  
    17.                 child.setVisibility(View.GONE);  
    18.   
    19.                 int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2)  
    20.                         * i));  
    21.                 int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2)  
    22.                         * i));  
    23.                 // childview width  
    24.                 int cWidth = child.getMeasuredWidth();  
    25.                 // childview height  
    26.                 int cHeight = child.getMeasuredHeight();  
    27.   
    28.                 // 右上,右下  
    29.                 if (mPosition == Position.LEFT_BOTTOM  
    30.                         || mPosition == Position.RIGHT_BOTTOM)  
    31.                 {  
    32.                     ct = getMeasuredHeight() - cHeight - ct;  
    33.                 }  
    34.                 // 右上,右下  
    35.                 if (mPosition == Position.RIGHT_TOP  
    36.                         || mPosition == Position.RIGHT_BOTTOM)  
    37.                 {  
    38.                     cl = getMeasuredWidth() - cWidth - cl;  
    39.                 }  
    40.   
    41.                 Log.e(TAG, cl + ” , ” + ct);  
    42.                 child.layout(cl, ct, cl + cWidth, ct + cHeight);  
    43.   
    44.             }  
    45.         }  
    46.     }  
    @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b)
        {
            if (changed)
            {
    
                layoutButton();
                int count = getChildCount();
                /**
                 * 设置所有孩子的位置 例如(第一个为按钮): 左上时,从左到右 ] 第2个:mRadius(sin0 , cos0)
                 * 第3个:mRadius(sina ,cosa) 注:[a = Math.PI / 2 * (cCount - 1)]
                 * 第4个:mRadius(sin2a ,cos2a) 第5个:mRadius(sin3a , cos3a) ...
                 */
                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));
                    // childview width
                    int cWidth = child.getMeasuredWidth();
                    // childview height
                    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;
                    }
    
                    Log.e(TAG, cl + " , " + ct);
                    child.layout(cl, ct, cl + cWidth, ct + cHeight);
    
                }
            }
        }

    首先在layoutButton中对按钮位置就行设置,以及初始化点击事件;然后从第二个子元素开始为菜单项,分别设置其位置,计算的原理就是上面我画的草图,可以再去仔细看看,动手在纸上画一画。

    1. /** 
    2.  * 第一个子元素为按钮,为按钮布局且初始化点击事件 
    3.  */  
    4. private void layoutButton()  
    5. {  
    6.     View cButton = getChildAt(0);  
    7.   
    8.     cButton.setOnClickListener(this);  
    9.   
    10.     int l = 0;  
    11.     int t = 0;  
    12.     int width = cButton.getMeasuredWidth();  
    13.     int height = cButton.getMeasuredHeight();  
    14.     switch (mPosition)  
    15.     {  
    16.     case LEFT_TOP:  
    17.         l = 0;  
    18.         t = 0;  
    19.         break;  
    20.     case LEFT_BOTTOM:  
    21.         l = 0;  
    22.         t = getMeasuredHeight() - height;  
    23.         break;  
    24.     case RIGHT_TOP:  
    25.         l = getMeasuredWidth() - width;  
    26.         t = 0;  
    27.         break;  
    28.     case RIGHT_BOTTOM:  
    29.         l = getMeasuredWidth() - width;  
    30.         t = getMeasuredHeight() - height;  
    31.         break;  
    32.   
    33.     }  
    34.     Log.e(TAG, l + ” , ” + t + “ , ” + (l + width) + “ , ” + (t + height));  
    35.     cButton.layout(l, t, l + width, t + height);  
    36.   
    37. }  
        /**
         * 第一个子元素为按钮,为按钮布局且初始化点击事件
         */
        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;
    
            }
            Log.e(TAG, l + " , " + t + " , " + (l + width) + " , " + (t + height));
            cButton.layout(l, t, l + width, t + height);
    
        }

    这是定位Button的代码,此时的代码已经实现了定位,如果你把onLayout中childView.setVisibility(VISIBLE)。ArcMenu的整个控件的样子已经实现了,接下来就是点击事件,已经效果动画的实现了。

    6、设置按钮点击事件

    1. /** 
    2.      * 为按钮添加点击事件 
    3.      */  
    4.     @Override  
    5.     public void onClick(View v)  
    6.     {  
    7.         mButton = findViewById(R.id.id_button);  
    8.         if (mButton == null)  
    9.         {  
    10.             mButton = getChildAt(0);  
    11.         }  
    12.         rotateView(mButton, 0f, 270f, 300);  
    13.         toggleMenu(300);  
    14.     }  
    /**
         * 为按钮添加点击事件
         */
        @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);
        }

    1. /** 
    2.      * 按钮的旋转动画 
    3.      *  
    4.      * @param view 
    5.      * @param fromDegrees 
    6.      * @param toDegrees 
    7.      * @param durationMillis 
    8.      */  
    9.     public static void rotateView(View view, float fromDegrees,  
    10.             float toDegrees, int durationMillis)  
    11.     {  
    12.         RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees,  
    13.                 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,  
    14.                 0.5f);  
    15.         rotate.setDuration(durationMillis);  
    16.         rotate.setFillAfter(true);  
    17.         view.startAnimation(rotate);  
    18.     }  
    19.   
    20.     public void toggleMenu(int durationMillis)  
    21.     {  
    22.         int count = getChildCount();  
    23.         for (int i = 0; i < count - 1; i++)  
    24.         {  
    25.             final View childView = getChildAt(i + 1);  
    26.             childView.setVisibility(View.VISIBLE);  
    27.   
    28.             int xflag = 1;  
    29.             int yflag = 1;  
    30.   
    31.             if (mPosition == Position.LEFT_TOP  
    32.                     || mPosition == Position.LEFT_BOTTOM)  
    33.                 xflag = -1;  
    34.             if (mPosition == Position.LEFT_TOP  
    35.                     || mPosition == Position.RIGHT_TOP)  
    36.                 yflag = -1;  
    37.   
    38.             // child left  
    39.             int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));  
    40.             // child top  
    41.             int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));  
    42.   
    43.             AnimationSet animset = new AnimationSet(true);  
    44.             Animation animation = null;  
    45.             if (mCurrentStatus == Status.CLOSE)  
    46.             {// to open  
    47.                 animset.setInterpolator(new OvershootInterpolator(2F));  
    48.                 animation = new TranslateAnimation(xflag * cl, 0, yflag * ct, 0);  
    49.                 childView.setClickable(true);  
    50.                 childView.setFocusable(true);  
    51.             } else  
    52.             {// to close  
    53.                 animation = new TranslateAnimation(0f, xflag * cl, 0f, yflag  
    54.                         * ct);  
    55.                 childView.setClickable(false);  
    56.                 childView.setFocusable(false);  
    57.             }  
    58.             animation.setAnimationListener(new AnimationListener()  
    59.             {  
    60.                 public void onAnimationStart(Animation animation)  
    61.                 {  
    62.                 }  
    63.   
    64.                 public void onAnimationRepeat(Animation animation)  
    65.                 {  
    66.                 }  
    67.   
    68.                 public void onAnimationEnd(Animation animation)  
    69.                 {  
    70.                     if (mCurrentStatus == Status.CLOSE)  
    71.                         childView.setVisibility(View.GONE);  
    72.   
    73.                 }  
    74.             });  
    75.   
    76.             animation.setFillAfter(true);  
    77.             animation.setDuration(durationMillis);  
    78.             // 为动画设置一个开始延迟时间,纯属好看,可以不设  
    79.             animation.setStartOffset((i * 100) / (count - 1));  
    80.             RotateAnimation rotate = new RotateAnimation(0720,  
    81.                     Animation.RELATIVE_TO_SELF, 0.5f,  
    82.                     Animation.RELATIVE_TO_SELF, 0.5f);  
    83.             rotate.setDuration(durationMillis);  
    84.             rotate.setFillAfter(true);  
    85.             animset.addAnimation(rotate);  
    86.             animset.addAnimation(animation);  
    87.             childView.startAnimation(animset);  
    88.             final int index = i + 1;  
    89.             childView.setOnClickListener(new View.OnClickListener()  
    90.             {  
    91.                 @Override  
    92.                 public void onClick(View v)  
    93.                 {  
    94.                     if (onMenuItemClickListener != null)  
    95.                         onMenuItemClickListener.onClick(childView, index - 1);  
    96.                     menuItemAnin(index - 1);  
    97.                     changeStatus();  
    98.                       
    99.                 }  
    100.             });  
    101.   
    102.         }  
    103.         changeStatus();  
    104.         Log.e(TAG, mCurrentStatus.name() +”“);  
    105.     }  
    /**
         * 按钮的旋转动画
         * 
         * @param view
         * @param fromDegrees
         * @param toDegrees
         * @param durationMillis
         */
        public static 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);
        }
    
        public void toggleMenu(int durationMillis)
        {
            int count = getChildCount();
            for (int i = 0; i < count - 1; i++)
            {
                final View childView = getChildAt(i + 1);
                childView.setVisibility(View.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;
    
                // child left
                int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));
                // child top
                int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));
    
                AnimationSet animset = new AnimationSet(true);
                Animation animation = null;
                if (mCurrentStatus == Status.CLOSE)
                {// to open
                    animset.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.setClickable(false);
                    childView.setFocusable(false);
                }
                animation.setAnimationListener(new AnimationListener()
                {
                    public void onAnimationStart(Animation animation)
                    {
                    }
    
                    public void onAnimationRepeat(Animation animation)
                    {
                    }
    
                    public void onAnimationEnd(Animation animation)
                    {
                        if (mCurrentStatus == Status.CLOSE)
                            childView.setVisibility(View.GONE);
    
                    }
                });
    
                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);
                animset.addAnimation(rotate);
                animset.addAnimation(animation);
                childView.startAnimation(animset);
                final int index = i + 1;
                childView.setOnClickListener(new View.OnClickListener()
                {
                    @Override
                    public void onClick(View v)
                    {
                        if (onMenuItemClickListener != null)
                            onMenuItemClickListener.onClick(childView, index - 1);
                        menuItemAnin(index - 1);
                        changeStatus();
    
                    }
                });
    
            }
            changeStatus();
            Log.e(TAG, mCurrentStatus.name() +"");
        }
    

    点击时,触发TanslateAnimation动画,从定点向外扩展,也给点击按钮添加了一个旋转动画,每个子菜单项同样添加了旋转动画,且如果用户设置回调,调用回调接口;设置子菜单的点击事件。整体就是点击然后动画效果~~

    7、设置子菜单的点击事件

    1. /** 
    2.      * 开始菜单动画,点击的MenuItem放大消失,其他的缩小消失 
    3.      * @param item 
    4.      */  
    5.     private void menuItemAnin(int item)  
    6.     {  
    7.         for (int i = 0; i < getChildCount() - 1; i++)  
    8.         {  
    9.             View childView = getChildAt(i + 1);  
    10.             if (i == item)  
    11.             {  
    12.                 childView.startAnimation(scaleBigAnim(300));  
    13.             } else  
    14.             {  
    15.                 childView.startAnimation(scaleSmallAnim(300));  
    16.             }  
    17.             childView.setClickable(false);  
    18.             childView.setFocusable(false);  
    19.   
    20.         }  
    21.   
    22.     }  
    23.       
    24.     /** 
    25.      * 缩小消失 
    26.      * @param durationMillis 
    27.      * @return 
    28.      */  
    29.     private Animation scaleSmallAnim(int durationMillis)  
    30.     {  
    31.         Animation anim = new ScaleAnimation(1.0f, 0f, 1.0f, 0f,  
    32.                 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,  
    33.                 0.5f);  
    34.         anim.setDuration(durationMillis);  
    35.         anim.setFillAfter(true);  
    36.         return anim;  
    37.     }  
    38.     /** 
    39.      * 放大,透明度降低 
    40.      * @param durationMillis 
    41.      * @return 
    42.      */  
    43.     private Animation scaleBigAnim(int durationMillis)  
    44.     {  
    45.         AnimationSet animationset = new AnimationSet(true);  
    46.   
    47.         Animation anim = new ScaleAnimation(1.0f, 4.0f, 1.0f, 4.0f,  
    48.                 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,  
    49.                 0.5f);  
    50.         Animation alphaAnimation = new AlphaAnimation(10);  
    51.         animationset.addAnimation(anim);  
    52.         animationset.addAnimation(alphaAnimation);  
    53.         animationset.setDuration(durationMillis);  
    54.         animationset.setFillAfter(true);  
    55.         return animationset;  
    56.     }  
    /**
         * 开始菜单动画,点击的MenuItem放大消失,其他的缩小消失
         * @param item
         */
        private void menuItemAnin(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 durationMillis
         * @return
         */
        private Animation scaleSmallAnim(int durationMillis)
        {
            Animation anim = new ScaleAnimation(1.0f, 0f, 1.0f, 0f,
                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                    0.5f);
            anim.setDuration(durationMillis);
            anim.setFillAfter(true);
            return anim;
        }
        /**
         * 放大,透明度降低
         * @param durationMillis
         * @return
         */
        private Animation scaleBigAnim(int durationMillis)
        {
            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(durationMillis);
            animationset.setFillAfter(true);
            return animationset;
        }

    点击的菜单项变大且慢慢透明消失,未点击的菜单项缩小消失~有兴趣的可以改成自己喜欢的动画~

    注:动画效果很多借鉴了eoe上那位仁兄的代码,这类动画也比较简单,就不多说了~


    好了,剩下就是些getter,setter了~

    8、布局文件:

    1. <RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”  
    2.     xmlns:tools=“http://schemas.android.com/tools”  
    3.     xmlns:zhy=“http://schemas.android.com/apk/res/com.example.zhy_arcmenu”  
    4.     android:layout_width=“match_parent”  
    5.     android:layout_height=“match_parent” >  
    6.   
    7.     <com.example.zhy_arcmenu.ArcMenu  
    8.         android:id=“@+id/id_arcmenu1”  
    9.         android:layout_width=“fill_parent”  
    10.         android:layout_height=“fill_parent”  
    11.         zhy:position=“left_top”  
    12.         zhy:radius=“130dp” >  
    13.   
    14.         <RelativeLayout  
    15.             android:layout_width=“wrap_content”  
    16.             android:layout_height=“wrap_content”  
    17.             android:background=“@drawable/composer_button” >  
    18.   
    19.             <ImageView  
    20.                 android:id=“@+id/id_button”  
    21.                 android:layout_width=“wrap_content”  
    22.                 android:layout_height=“wrap_content”  
    23.                 android:layout_centerInParent=“true”  
    24.                 android:src=“@drawable/composer_icn_plus” />  
    25.         </RelativeLayout>  
    26.   
    27.         <ImageView  
    28.             android:layout_width=“wrap_content”  
    29.             android:layout_height=“wrap_content”  
    30.             android:layout_centerInParent=“true”  
    31.             android:src=“@drawable/composer_camera”  
    32.             android:tag=“Camera” />  
    33.   
    34.         <ImageView  
    35.             android:layout_width=“wrap_content”  
    36.             android:layout_height=“wrap_content”  
    37.             android:layout_centerInParent=“true”  
    38.             android:src=“@drawable/composer_sun”  
    39.             android:tag=“Sun” />  
    40.   
    41.         <ImageView  
    42.             android:layout_width=“wrap_content”  
    43.             android:layout_height=“wrap_content”  
    44.             android:layout_centerInParent=“true”  
    45.             android:src=“@drawable/composer_place”  
    46.             android:tag=“Place” />  
    47.           
    48.         <ImageView  
    49.             android:layout_width=“wrap_content”  
    50.             android:layout_height=“wrap_content”  
    51.             android:layout_centerInParent=“true”  
    52.             android:src=“@drawable/composer_sleep”  
    53.             android:tag=“Sleep” />  
    54.   
    55.     </com.example.zhy_arcmenu.ArcMenu>  
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:zhy="http://schemas.android.com/apk/res/com.example.zhy_arcmenu"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <com.example.zhy_arcmenu.ArcMenu
            android:id="@+id/id_arcmenu1"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            zhy:position="left_top"
            zhy:radius="130dp" >
    
            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/composer_button" >
    
                <ImageView
                    android:id="@+id/id_button"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:src="@drawable/composer_icn_plus" />
            </RelativeLayout>
    
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:src="@drawable/composer_camera"
                android:tag="Camera" />
    
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:src="@drawable/composer_sun"
                android:tag="Sun" />
    
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:src="@drawable/composer_place"
                android:tag="Place" />
    
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:src="@drawable/composer_sleep"
                android:tag="Sleep" />
    
        </com.example.zhy_arcmenu.ArcMenu>

    嗯,第一个元素为按钮,其他的都是菜单项了~~喜欢用代码的,也可以代码生成,我是比较喜欢布局文件中写这些玩意~

    9、MainActivity

    1. package com.example.zhy_arcmenu;  
    2.   
    3. import android.app.Activity;  
    4. import android.os.Bundle;  
    5. import android.view.View;  
    6. import android.view.Window;  
    7. import android.widget.ImageView;  
    8. import android.widget.Toast;  
    9.   
    10. import com.example.zhy_arcmenu.ArcMenu.OnMenuItemClickListener;  
    11.   
    12. public class MainActivity extends Activity  
    13. {  
    14.   
    15.     private ArcMenu mArcMenuLeftTop;  
    16.   
    17.     @Override  
    18.     protected void onCreate(Bundle savedInstanceState)  
    19.     {  
    20.         super.onCreate(savedInstanceState);  
    21.         setContentView(R.layout.activity_main);  
    22.         mArcMenuLeftTop = (ArcMenu) findViewById(R.id.id_arcmenu1);  
    23.         //动态添加一个MenuItem  
    24.         ImageView people = new ImageView(this);  
    25.         people.setImageResource(R.drawable.composer_with);  
    26.         people.setTag(”People”);  
    27.         mArcMenuLeftTop.addView(people);  
    28.   
    29.       
    30.         mArcMenuLeftTop  
    31.                 .setOnMenuItemClickListener(new OnMenuItemClickListener()  
    32.                 {  
    33.                     @Override  
    34.                     public void onClick(View view, int pos)  
    35.                     {  
    36.                         Toast.makeText(MainActivity.this,  
    37.                                 pos + ”:” + view.getTag(), Toast.LENGTH_SHORT)  
    38.                                 .show();  
    39.                     }  
    40.                 });  
    41.     }  
    42.   
    43. }  
    package com.example.zhy_arcmenu;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.Window;
    import android.widget.ImageView;
    import android.widget.Toast;
    
    import com.example.zhy_arcmenu.ArcMenu.OnMenuItemClickListener;
    
    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.drawable.composer_with);
            people.setTag("People");
            mArcMenuLeftTop.addView(people);
    
    
            mArcMenuLeftTop
                    .setOnMenuItemClickListener(new OnMenuItemClickListener()
                    {
                        @Override
                        public void onClick(View view, int pos)
                        {
                            Toast.makeText(MainActivity.this,
                                    pos + ":" + view.getTag(), Toast.LENGTH_SHORT)
                                    .show();
                        }
                    });
        }
    
    }
    



    结束~~有任何意见欢迎指出~~


    源码点击下载




    展开全文
  • 安卓Android源码——ArcMenu仿path按钮.zip
  • 整合了SldingMenu、ArcMenu、MenuDrawer、WheelMenu、SatelliteMenu、RatialMenu等优秀的关于Menu的开源项目。  本实例整合了关于Android Menu的优秀开源代码,方便有需要用到Menu开源项目的小伙伴使用。 一、整合...
  • 安卓Android源码——ArcMenu-path菜单master.zip
  • TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcMenu, defStyle, 0); int count = array.getIndexCount(); for (int i = 0; i ; i++) { int index = array.getIndex(i); ...
  • 一个不错的ArcMenu

    2019-08-09 01:09:12
    NULL 博文链接:https://gundumw100.iteye.com/blog/2178840
  • 具体功能 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_...
  • 直接调用,快捷实现arcmenu,供参考,详见博客http://blog.csdn.net/yaodong379/article/details/51824779

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,615
精华内容 646
热门标签
关键字:

arcmenu