Android环形旋转菜单

本Demo属于自定义View的内容,主要是应用已有的控件,结合属性动画而达到相应功能效果,源码已经push在Github

先看效果图:

这里写图片描述


一、布局

布局相对比较简单,主要用到Relativelayout布局,结合ImageButton和资源图片构成。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.project.codingma.ringmenu.MainActivity">

    <RelativeLayout
        android:id="@+id/rl_level1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1">

        <ImageButton
            android:id="@+id/ib_home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@null"
            android:src="@drawable/icon_home" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_level2"
        android:layout_width="180dp"
        android:layout_height="90dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2">

        <ImageButton
            android:id="@+id/ib_menu"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:background="@null"
            android:src="@drawable/icon_menu" />

        <ImageButton
            android:id="@+id/icon_search"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="5dp"
            android:background="@null"
            android:src="@drawable/icon_search" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginRight="5dp"
            android:background="@null"
            android:src="@drawable/icon_myyouku" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_level3"
        android:layout_width="280dp"
        android:layout_height="140dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3">

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_marginBottom="5dp"
            android:layout_marginLeft="10dp"
            android:background="@null"
            android:src="@drawable/channel1" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="30dp"
            android:layout_marginTop="50dp"
            android:background="@null"
            android:src="@drawable/channel2" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="65dp"
            android:layout_marginTop="20dp"
            android:background="@null"
            android:src="@drawable/channel3" />

        <ImageButton
            android:id="@+id/imageButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"
            android:background="@null"
            android:src="@drawable/channel4" />


        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_marginRight="65dp"
            android:layout_marginTop="20dp"
            android:background="@null"
            android:src="@drawable/channel6" />

        <ImageButton
            android:id="@+id/imageButton2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="5dp"
            android:layout_marginRight="10dp"
            android:background="@null"
            android:src="@drawable/channel7" />

        <ImageButton
            android:id="@+id/imageButton3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignEnd="@+id/imageButton2"
            android:layout_below="@+id/imageButton"
            android:layout_marginEnd="10dp"
            android:layout_marginRight="30dp"
            android:background="@null"
            android:src="@drawable/channel5" />
    </RelativeLayout>
</RelativeLayout>


二、给指定的控件添加逻辑事件

绑定好相应的控件,同时设置监听事件
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //初始化控件
        initViews();
    }

    /**
     * 初始化控件
     */
    private void initViews() {

        //设置监听事件
        findViewById(R.id.ib_menu).setOnClickListener(this);
        findViewById(R.id.ib_home).setOnClickListener(this);
    }

三、明确业务,执行动画

整个demo可以分为3级菜单,最外层为第三级,以此类推,当按第2级菜单栏home按钮,最外层则相应的转出或转入;当按第1级的home按钮,则最外两层相应的转入或转出,并且要有一定的时间差。
(1)动画效果的代码:
/**
 * 动画类
 * Created by Sean on 2017/1/26.
 */

public class AnimationUtils {

    //正在运行的动画个数,防止动画未执行完就执行下次动画
    public static int runningAnimationCount = 0;

    /**
     * 设置转出的动画
     *
     * @param layout 需要动画效果的layout
     * @param delay  动画开始后的延时时间
     */
    public static void rotateOutAnim(RelativeLayout layout, long delay) {

        //由于补间动画的局限性,在设置动画退出时要让所有子View无法响应
        int childCount = layout.getChildCount();
        for (int i = 0; i < childCount; i++) {
            layout.getChildAt(i).setEnabled(false);
        }


        RotateAnimation ra = new RotateAnimation(
                0f, -180f, //开始,结束的角度,逆时针
                Animation.RELATIVE_TO_SELF, 0.5f,  //相对于布局的x坐标
                Animation.RELATIVE_TO_SELF, 1.0f); //相对于布局的y坐标

        ra.setDuration(500);
        ra.setFillAfter(true);  //设置动画留在结束位置
        ra.setStartOffset(delay); //设置动画延时
        ra.setAnimationListener(new MyAnimationListener()); //设置监听事件

        layout.setAnimation(ra);
    }

    /**
     * 转入动画
     *
     * @param layout 需要动画效果的layout
     * @param delay  动画开始后的延时时间
     */
    public static void rotateInAnim(RelativeLayout layout, long delay) {
        int childCount = layout.getChildCount();
        for (int i = 0; i < childCount; i++) {
            layout.getChildAt(i).setEnabled(true);
        }

        RotateAnimation ra = new RotateAnimation(
                -180f, 0f, //开始,结束的角度,逆时针
                Animation.RELATIVE_TO_SELF, 0.5f,  //相对于布局的x坐标
                Animation.RELATIVE_TO_SELF, 1.0f); //相对于布局的y坐标

        ra.setDuration(500);
        ra.setFillAfter(true);  //设置动画留在结束位置
        ra.setStartOffset(delay); //设置动画延时
        ra.setAnimationListener(new MyAnimationListener()); //设置监听事件

        layout.setAnimation(ra);
    }

    /**
     * 动画的监听事件
     */
    static class MyAnimationListener implements Animation.AnimationListener {

        @Override
        public void onAnimationStart(Animation animation) {
            runningAnimationCount++;
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            runningAnimationCount--;
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    }
}
(2)逻辑代码:
@Override
    public void onClick(View v) {
        if (AnimationUtils.runningAnimationCount > 0) {
            //有动画在运行
            return;
        }
        switch (v.getId()) {
            case R.id.ib_home:
                if (isLevel2Display) {
                    long delay = 0;
                    if (isLevel3Display) {
                        //三级菜单转出
                        AnimationUtils.rotateOutAnim(rlLevel3, delay);
                        isLevel3Display = false;
                        delay += 200;

                        //二级菜单转出
                        AnimationUtils.rotateOutAnim(rlLevel2, delay);
                    }
                } else {
                    AnimationUtils.rotateInAnim(rlLevel2, 0);
                }

                //置反
                isLevel2Display = !isLevel2Display;
                break;
            case R.id.ib_menu:
                if (isLevel3Display) {
                    AnimationUtils.rotateOutAnim(rlLevel3, 0);
                } else {
                    AnimationUtils.rotateInAnim(rlLevel3, 0);
                }

                isLevel3Display = !isLevel3Display;
                break;
            default:
                break;
        }
    }

四、菜单按钮的监听

针对拥有菜单按钮的android设备,通过菜单home键,可以实现所有菜单栏(包括三级菜单)转出或转入。
@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        //返回ture才可以实现监听事件
        if (keyCode == KeyEvent.KEYCODE_MENU) {
            if (AnimationUtils.runningAnimationCount > 0) {
                // 当前有动画正在执行, 取消当前事件
                return true;
            }


            if (isLevel1Display) {
                long delay = 0;

                //隐藏三级菜单
                if (isLevel3Display) {
                    AnimationUtils.rotateOutAnim(rlLevel3, delay);
                    isLevel3Display = !isLevel3Display;
                    delay += 200;
                }

                //隐藏二级菜单
                if (isLevel2Display) {
                    AnimationUtils.rotateOutAnim(rlLevel2, delay);
                    isLevel2Display = !isLevel2Display;
                    delay += 200;
                }

                //隐藏一级菜单
                AnimationUtils.rotateOutAnim(rlLevel3, delay);
            } else {
                // 顺次转进来
                AnimationUtils.rotateInAnim(rlLevel1, 0);
                AnimationUtils.rotateInAnim(rlLevel2, 200);
                AnimationUtils.rotateInAnim(rlLevel3, 400);

                isLevel3Display = true;
                isLevel2Display = true;
            }

            isLevel1Display = !isLevel1Display;
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

以上是笔者的一个小Demo,若有兴趣可以上github上下载源码https://github.com/codingma/RingMenu

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值