zoukankan      html  css  js  c++  java
  • android自定义控件之模仿优酷菜单

    去年的优酷HD版有过这样一种菜单,如下图:

    这里写图片描述

    应用打开之后,先是三个弧形的三级菜单,点击实体键menu之后,这三个菜单依次旋转退出,再点击实体键menu之后,一级菜单会旋转进入,点击一级菜单,二级菜单旋转进入,点击二级菜单的menu键,三级菜单旋转进入,再次点击二级菜单的旋转键,三级菜单又会旋转退出,这时再点击一级菜单,二级菜单退出,最后点击实体menu键,一级菜单退出。

    总体来说实现这样的功能:
    (1)点击实体menu键时,如果界面上有菜单显示,不管有几个,全部依次退出,如果界面上没有菜单显示,则显示一级菜单。
    (2)点击一级菜单的home键时,如果此时界面只有一级菜单,则显示二级菜单,否则让除了一级菜单外的菜单全都依次退出。
    (3)点击二级菜单的menu键时,如果三级菜单已经显示,则让它旋转退出,如果三级菜单未显示则让它旋转进入。

    好了,今天我们主要实现上述效果。

    先来看布局文件

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.customwidget.MainActivity" >
    
        <RelativeLayout
            android:id="@+id/menu_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/level1_home"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:layout_marginBottom="10dp"
                android:background="@drawable/icon_home"
                android:onClick="myClick" />
        </RelativeLayout>
    
        <RelativeLayout
            android:id="@+id/menu_level2"
            android:layout_width="200dp"
            android:layout_height="100dp"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:background="@drawable/level2" >
    
            <ImageButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_marginBottom="10dp"
                android:layout_marginLeft="15dp"
                android:background="@drawable/icon_search" />
    
            <ImageButton
                android:id="@+id/level2_menu"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="7dp"
                android:background="@drawable/icon_menu"
                android:onClick="myClick" />
    
            <ImageButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_alignParentRight="true"
                android:layout_marginBottom="10dp"
                android:layout_marginRight="15dp"
                android:background="@drawable/icon_myyouku" />
        </RelativeLayout>
    
        <RelativeLayout
            android:id="@+id/menu_level3"
            android:layout_width="320dp"
            android:layout_height="162dp"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:background="@drawable/level3" >
    
            <ImageButton
                android:id="@+id/level3_channel1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_marginBottom="10dp"
                android:layout_marginLeft="12dp"
                android:background="@drawable/channel1" />
    
            <ImageButton
                android:id="@+id/level3_channel2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_above="@id/level3_channel1"
                android:layout_marginBottom="17dp"
                android:layout_marginLeft="-5dp"
                android:layout_toRightOf="@id/level3_channel1"
                android:background="@drawable/channel2" />
    
            <ImageButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_above="@id/level3_channel2"
                android:layout_marginBottom="15dp"
                android:layout_marginLeft="13dp"
                android:layout_toRightOf="@id/level3_channel2"
                android:background="@drawable/channel3" />
    
            <ImageButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="10dp"
                android:background="@drawable/channel4" />
    
            <ImageButton
                android:id="@+id/level3_channel7"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_alignParentRight="true"
                android:layout_marginBottom="10dp"
                android:layout_marginRight="12dp"
                android:background="@drawable/channel7" />
    
            <ImageButton
                android:id="@+id/level3_channel6"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_above="@id/level3_channel7"
                android:layout_marginBottom="17dp"
                android:layout_marginRight="-5dp"
                android:layout_toLeftOf="@id/level3_channel7"
                android:background="@drawable/channel6" />
    
            <ImageButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_above="@id/level3_channel6"
                android:layout_marginBottom="15dp"
                android:layout_marginRight="13dp"
                android:layout_toLeftOf="@id/level3_channel6"
                android:background="@drawable/channel5" />
        </RelativeLayout>
    
    </RelativeLayout>

    这里是一个相对布局中嵌套了三个相对布局,嵌套的第一个相对布局负责显示一级菜单,嵌套的第二个相对布局负责显示二级菜单,嵌套的第三个相对布局负责显示三级菜单。三个不同层次的菜单的背景都是弧形。我们通过指定具体的宽高来使三个层次的菜单具有不同的大小。

    效果如下:

    这里写图片描述

    再看看MainActivity.java

    /**
     * 模仿优酷菜单
     * 2015年5月19日
     */
    public class MainActivity extends Activity {
    
        //分别拿到不同等级的菜单
        private RelativeLayout lv1;
        private RelativeLayout lv2;
        private RelativeLayout lv3;
        private Animation animation;
        //各级菜单是否显示,默认全都显示
        private boolean isDisplaylv1 = true;
        private boolean isDisplaylv2 = true;
        private boolean isDisplaylv3 = true;
        //动画是否正在执行,默认动画没有执行
        private boolean isAnimationRunning = false;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            lv1 = (RelativeLayout) this.findViewById(R.id.menu_level1);
            lv2 = (RelativeLayout) this.findViewById(R.id.menu_level2);
            lv3 = (RelativeLayout) this.findViewById(R.id.menu_level3);
        }
    
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            //如果动画正在执行,则不处理此事件
            if (isAnimationRunning)
                return super.onKeyDown(keyCode, event);
            //如果点击的是菜单键
            if (keyCode == KeyEvent.KEYCODE_MENU) {
                //如果一级菜单已经显示,判断二级菜单是否显示
                if (isDisplaylv1) {
                    //设置动画启动延迟时间
                    int startOffset = 0;
                    //如果二级菜单已经显示,判断三级菜单是否显示,然后退出二级菜单
                    if (isDisplaylv2) {
                        if (isDisplaylv3) {
                            //如果三级菜单已经显示,执行退出动画
                            exitAnimation(lv3, startOffset);
                            //三级菜单退出动画执行完毕之后,动画的启动时间延迟500ms
                            startOffset += 500;
                            isDisplaylv3 = !isDisplaylv3;
                        }
                        //二级菜单退出,此时startOffset=500,即动画启动时间延迟500ms
                        exitAnimation(lv2, startOffset);
                        //二级菜单退出动画执行完毕之后,动画的启动时间延迟500ms
                        startOffset += 500;
                        isDisplaylv2 = !isDisplaylv2;
                    }
                    //一级菜单退出,此时startOffset=1000,即动画启动时间延迟1000ms
                    exitAnimation(lv1, startOffset);
                //如果一级菜单未显示,则一级菜单进入
                } else {
                    enterAnimation(lv1);
                }
                isDisplaylv1 = !isDisplaylv1;
                return true;
            }
            return super.onKeyDown(keyCode, event);
        }
    
        public void myClick(View v) {
            //如果动画正在执行,则不处理此事件
            if (isAnimationRunning)
                return;
            switch (v.getId()) {
            /**
             * 当点击二级菜单的menu时,如果三级菜单已经显示,则执行退出动画,
             * 否则执行进入动画
             */
            case R.id.level2_menu:
                if (isDisplaylv3) {
                    exitAnimation(lv3, 0);
                } else {
                    enterAnimation(lv3);
                }
                isDisplaylv3 = !isDisplaylv3;
                break;
            case R.id.level1_home:
                // 如果二级菜单已经显示,再判断三级菜单是否显示
                if (isDisplaylv2) {
                    //通过设置动画启动延迟时间,来实现动画依次退出效果
                    int startOffset = 0;
                    // 如果三级菜单也显示了,则让他们依次退出
                    if (isDisplaylv3) {
                        exitAnimation(lv3, startOffset);
                        startOffset = 700;
                        isDisplaylv3 = !isDisplaylv3;
                    }
                    exitAnimation(lv2, startOffset);
                    isDisplaylv2 = !isDisplaylv2;
                    // 如果二级菜单没有显示,就让二级菜单显示出来
                } else {
                    enterAnimation(lv2);
                    isDisplaylv2 = !isDisplaylv2;
                }
                break;
            }
        }
    
        /**
         * 退出动画
         * @param layout 执行动画的布局文件
         * @param startOffset 动画启动的延迟时间
         */
        public void exitAnimation(RelativeLayout layout, long startOffset) {
            animation = AnimationUtils.loadAnimation(this, R.anim.exit_menu);
            animation.setFillAfter(true);
            animation.setStartOffset(startOffset);
            animation.setAnimationListener(new MyAnimationListener());
            layout.startAnimation(animation);
        }
    
        /**
         * 进入动画
         * @param layout 执行动画的布局文件
         */
        public void enterAnimation(RelativeLayout layout) {
            animation = AnimationUtils.loadAnimation(this, R.anim.enter_menu);
            animation.setFillAfter(true);
            animation.setAnimationListener(new MyAnimationListener());
            layout.startAnimation(animation);
        }
    
        /**
         * 判断动画是否正在执行
         * @author 王松
         *
         */
        private class MyAnimationListener implements AnimationListener {
    
            //动画开始执行
            @Override
            public void onAnimationStart(Animation animation) {
                isAnimationRunning = true;
            }
    
            //动画执行结束
            @Override
            public void onAnimationEnd(Animation animation) {
                isAnimationRunning = false;
            }
    
            @Override
            public void onAnimationRepeat(Animation animation) {
            }
    
        }
    }

    代码中注释已经写的很详细了,这里不再赘述。最后在给大家看看两个动画文件:

    enter_menu.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:shareInterpolator="true">
        <rotate
            android:duration="1000"
            android:fromDegrees="-180"
            android:toDegrees="0"
            android:pivotX="50%"
            android:pivotY="100%" />
    </set>

    exit_menu.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:shareInterpolator="true">
        <rotate
            android:duration="1000"
            android:fromDegrees="0"
            android:toDegrees="-180"
            android:pivotX="50%"
            android:pivotY="100%" />
    </set>

    关于动画如果不太懂可以看这里android之tween动画详解android之frame动画详解。。

    本项目完整代码下载

  • 相关阅读:
    Proximal Gradient Descent for L1 Regularization
    使用Spring Security3的四种方法概述
    理解spring对事务的处理:传播性
    MySQL事务隔离级别详解
    Spring 使用注解方式进行事务管理
    Redis的高级应用-安全性和主从复制
    Redis的高级应用-事务处理、持久化、发布与订阅消息、虚拟内存使用
    mysql 语句优化心得
    Maven搭建Spring Security3.2项目详解
    Java网络编程之TCP、UDP
  • 原文地址:https://www.cnblogs.com/lenve/p/4517974.html
Copyright © 2011-2022 走看看