1.首先我们看看效果图:
这是优酷布局效果图:
2. 下面是我们最终编写的程序的效果图:
3. 下面就是详细演示这个效果的实现过程
(1)新建一个Android工程,命名为"优酷菜单",如下:
(2)这里的图片资源都是美工开发好的给我们的,如下:
我们把这些图片拷贝到res/drawable(工程图片资源文件),如下:
(3)三级菜单实现的效果如下,布局activity_main.xml,如下:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 tools:context="com.himi.youkumenu.MainActivity" > 6 7 <TextView 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:layout_centerHorizontal="true" 11 android:layout_centerVertical="true" 12 android:text="@string/hello_world" /> 13 14 <ImageView 15 android:id="@+id/level1" 16 android:layout_width="100dp" 17 android:layout_height="50dp" 18 android:layout_alignParentBottom="true" 19 android:layout_centerHorizontal="true" 20 android:background="@drawable/level1" /> 21 22 <ImageView 23 android:id="@+id/level2" 24 android:layout_width="180dp" 25 android:layout_height="90dp" 26 android:layout_alignParentBottom="true" 27 android:layout_centerHorizontal="true" 28 android:background="@drawable/level2" /> 29 30 <ImageView 31 android:id="@+id/level3" 32 android:layout_width="280dp" 33 android:layout_height="140dp" 34 android:layout_alignParentBottom="true" 35 android:layout_centerHorizontal="true" 36 android:background="@drawable/level3" /> 37 </RelativeLayout>
布局效果如下:
这样设计确实可以实现三级菜单的效果,但是后面每一级菜单上面都会有很多小图标,这里设置ImageView不利于后面菜单摆放图标,必须修改。
这里activity_main.xml修改,如下:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 tools:context="com.himi.youkumenu.MainActivity" > 6 7 <TextView 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:layout_centerHorizontal="true" 11 android:layout_centerVertical="true" 12 android:text="@string/hello_world" /> 13 14 <RelativeLayout 15 android:id="@+id/level1" 16 android:layout_width="100dp" 17 android:layout_height="50dp" 18 android:layout_alignParentBottom="true" 19 android:layout_centerHorizontal="true" 20 android:background="@drawable/level1" /> 21 22 <RelativeLayout 23 android:id="@+id/level2" 24 android:layout_width="180dp" 25 android:layout_height="90dp" 26 android:layout_alignParentBottom="true" 27 android:layout_centerHorizontal="true" 28 android:background="@drawable/level2" /> 29 30 <RelativeLayout 31 android:id="@+id/level3" 32 android:layout_width="280dp" 33 android:layout_height="140dp" 34 android:layout_alignParentBottom="true" 35 android:layout_centerHorizontal="true" 36 android:background="@drawable/level3" /> 37 </RelativeLayout>
把之前的ImageView改成RelativeLayout布局,方便之后每级菜单摆放小图标。
(4)接下来实现三级菜单的图标摆放,如下:
activity_main.xml,如下:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 tools:context="com.himi.youkumenu.MainActivity" > 6 7 <TextView 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:layout_centerHorizontal="true" 11 android:layout_centerVertical="true" 12 android:text="@string/hello_world" /> 13 14 <RelativeLayout 15 android:id="@+id/level1" 16 android:layout_width="100dp" 17 android:layout_height="50dp" 18 android:layout_alignParentBottom="true" 19 android:layout_centerHorizontal="true" 20 android:background="@drawable/level1" > 21 22 <ImageView 23 android:id="@+id/icon_home" 24 android:layout_width="wrap_content" 25 android:layout_height="wrap_content" 26 android:layout_centerInParent="true" 27 android:background="@drawable/icon_home" /> 28 </RelativeLayout> 29 30 <RelativeLayout 31 android:id="@+id/level2" 32 android:layout_width="180dp" 33 android:layout_height="90dp" 34 android:layout_alignParentBottom="true" 35 android:layout_centerHorizontal="true" 36 android:background="@drawable/level2" > 37 38 <ImageView 39 android:id="@+id/icon_search" 40 android:layout_width="wrap_content" 41 android:layout_height="wrap_content" 42 android:layout_alignParentBottom="true" 43 android:layout_margin="8dp" 44 android:background="@drawable/icon_search" /> 45 46 <ImageView 47 android:id="@+id/icon_menu" 48 android:layout_width="wrap_content" 49 android:layout_height="wrap_content" 50 android:layout_alignParentTop="true" 51 android:layout_centerHorizontal="true" 52 android:layout_marginTop="5dp" 53 android:background="@drawable/icon_menu" /> 54 55 <ImageView 56 android:id="@+id/icon_myyouku" 57 android:layout_width="wrap_content" 58 android:layout_height="wrap_content" 59 android:layout_alignParentBottom="true" 60 android:layout_alignParentRight="true" 61 android:layout_margin="8dp" 62 android:background="@drawable/icon_myyouku" /> 63 </RelativeLayout> 64 65 <RelativeLayout 66 android:id="@+id/level3" 67 android:layout_width="280dp" 68 android:layout_height="140dp" 69 android:layout_alignParentBottom="true" 70 android:layout_centerHorizontal="true" 71 android:background="@drawable/level3" > 72 73 <ImageView 74 android:id="@+id/channel1" 75 android:layout_width="wrap_content" 76 android:layout_height="wrap_content" 77 android:layout_alignParentBottom="true" 78 android:layout_marginBottom="10dp" 79 android:layout_marginLeft="10dp" 80 android:background="@drawable/channel1" /> 81 82 <ImageView 83 android:id="@+id/channel2" 84 android:layout_width="wrap_content" 85 android:layout_height="wrap_content" 86 android:layout_above="@id/channel1" 87 android:layout_alignLeft="@id/channel1" 88 android:layout_marginBottom="6dp" 89 android:layout_marginLeft="20dp" 90 android:background="@drawable/channel2" /> 91 92 <ImageView 93 android:id="@+id/channel3" 94 android:layout_width="wrap_content" 95 android:layout_height="wrap_content" 96 android:layout_above="@id/channel2" 97 android:layout_alignLeft="@id/channel2" 98 android:layout_marginBottom="6dp" 99 android:layout_marginLeft="30dp" 100 android:background="@drawable/channel3" /> 101 102 <ImageView 103 android:id="@+id/channel4" 104 android:layout_width="wrap_content" 105 android:layout_height="wrap_content" 106 android:layout_centerHorizontal="true" 107 android:layout_marginTop="5dp" 108 android:background="@drawable/channel4" /> 109 110 <ImageView 111 android:id="@+id/channel7" 112 android:layout_width="wrap_content" 113 android:layout_height="wrap_content" 114 android:layout_alignParentBottom="true" 115 android:layout_alignParentRight="true" 116 android:layout_marginBottom="10dp" 117 android:layout_marginRight="10dp" 118 android:background="@drawable/channel7" /> 119 120 <ImageView 121 android:id="@+id/channel6" 122 android:layout_width="wrap_content" 123 android:layout_height="wrap_content" 124 android:layout_above="@id/channel7" 125 android:layout_alignRight="@id/channel7" 126 android:layout_marginBottom="6dp" 127 android:layout_marginRight="20dp" 128 android:background="@drawable/channel6" /> 129 130 <ImageView 131 android:id="@+id/channel5" 132 android:layout_width="wrap_content" 133 android:layout_height="wrap_content" 134 android:layout_above="@id/channel6" 135 android:layout_alignRight="@id/channel6" 136 android:layout_marginBottom="6dp" 137 android:layout_marginRight="30dp" 138 android:background="@drawable/channel5" /> 139 </RelativeLayout> 140 141 </RelativeLayout>
布局效果如下:
这里第1级菜单 和 第2级菜单实现没什么好讲的,关键是第3级菜单,分析思路如下:
第3级菜单左右分为一半,同时channel4为中间一个。
左半部分:channel1为左半部分定位基准
•channel1为左边第一个,让它和父容器的底部对齐(默认是靠左),为了美观好看一点我们添加属性:android:layout_marginBottom="10dp" 和 android:layout_marginLeft="10dp"
•channel2是以channel1为基准进行对齐的,channel2在channel1右上角,但是只要实现channel2在channel1上面的属性:android:layout_above="@id/channel1",没有实现直接属性实现channel2在channel1的右边,该怎么办呢? 这里我们可以先让channel2和channel1进行左对齐,然后设置靠左的边距适当即可:android:layout_alignLeft="@id/channel1"(channel2和channel1左对齐),android:layout_marginLeft="20dp"(设置靠左边距)
•同样道理channel3是以channel2为基准进行对齐的,思路和上面一样。
右半部分:思路和上面过程是一致的,这个时候是以channel7为右半部分定位基准
•channel7为右半部分定位基准,而且channel7和channel1是对称的,这样的话,也就是channel7和channel1布局是一致只不过,左右位置调换,如下:
•其余也是对称设置,channel2 和channel6 ,channel3 和channel5
(5)下面就要实现代码部分,利用Animation旋转出现、消失菜单。
首先我们必须知道旋转的坐标系,如下:
(6)来到MainActivity,搭建实现逻辑框架,如下:
1 package com.himi.youkumenu; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.KeyEvent; 6 import android.view.View; 7 import android.view.View.OnClickListener; 8 import android.widget.ImageView; 9 import android.widget.RelativeLayout; 10 11 public class MainActivity extends Activity implements OnClickListener { 12 private ImageView icon_menu; 13 private ImageView icon_home; 14 15 private RelativeLayout level1; 16 private RelativeLayout level2; 17 private RelativeLayout level3; 18 /** 19 * 判断第3级菜单是否显示 20 * true 显示 (默认) 21 * false 隐藏 22 */ 23 private boolean isLevel3Show = true; 24 /** 25 * 判断2级菜单是否显示 26 * true 显示 (默认) 27 * false 隐藏 28 */ 29 private boolean isLevel2Show = true; 30 /** 31 * 判断1级菜单是否显示 32 * true 显示 (默认) 33 * false 隐藏 34 */ 35 private boolean isLevel1Show = true; 36 37 @Override 38 protected void onCreate(Bundle savedInstanceState) { 39 super.onCreate(savedInstanceState); 40 setContentView(R.layout.activity_main); 41 42 icon_home = (ImageView) findViewById(R.id.icon_home); 43 icon_menu = (ImageView) findViewById(R.id.icon_menu); 44 45 level1 = (RelativeLayout) findViewById(R.id.level1); 46 level2 = (RelativeLayout) findViewById(R.id.level2); 47 level3 = (RelativeLayout) findViewById(R.id.level3); 48 49 icon_home.setOnClickListener(this); 50 icon_menu.setOnClickListener(this); 51 } 52 53 public void onClick(View v) { 54 switch (v.getId()) { 55 case R.id.icon_menu:// 处理menu的点击的事件 56 // 如果第3级菜单是显示状态,那么将其隐藏 57 if (isLevel3Show) { 58 MyUtils.startAnimOut(level3); 59 } else { 60 // 如果第3级菜单是隐藏状态,那么将其显示 61 MyUtils.startAnimIn(level3); 62 } 63 64 isLevel3Show = !isLevel3Show; 65 break; 66 67 case R.id.icon_home:// 处理home的点击的事件 68 // 如果第2级菜单是显示状态,那么就隐藏2,3级菜单 69 if (isLevel2Show) { 70 MyUtils.startAnimOut(level2); 71 isLevel2Show = false; 72 73 if (isLevel3Show) {// 如果此时第3级菜单是显示状态,那么将其隐藏 74 75 // 这里不能使用Thread.sleep延迟时间,因为这个办法会是整个线程处于休眠状态,上面的2级菜单也不会旋转离开 76 MyUtils.startAnimOut(level3, 200); 77 isLevel3Show = false; 78 } 79 80 } else { 81 // 如果第2级菜单是隐藏状态,那么就显示2级菜单 82 MyUtils.startAnimIn(level2); 83 isLevel2Show = true; 84 } 85 86 break; 87 } 88 } 89 90 /** 91 * 监听按键的动作 92 */ 93 @Override 94 public boolean onKeyDown(int keyCode, KeyEvent event) { 95 if(keyCode == KeyEvent.KEYCODE_MENU) {//监听menu按键 96 changeLevelState(); 97 } 98 return super.onKeyDown(keyCode, event); 99 } 100 101 /** 102 * 改变第1级菜单的状态 103 */ 104 private void changeLevelState() { 105 //如果第1菜单是显示状态,隐藏1,2,3级菜单 106 107 if(isLevel1Show) { 108 MyUtils.startAnimOut(level1); 109 isLevel1Show = false; 110 111 if(isLevel2Show) { 112 MyUtils.startAnimOut(level2,100); 113 isLevel2Show = false; 114 115 if(isLevel3Show) { 116 MyUtils.startAnimOut(level3,200); 117 isLevel3Show = false; 118 } 119 } 120 121 } else { 122 //如果第1菜单是隐藏状态,显示1,2级菜单 123 MyUtils.startAnimIn(level1); 124 isLevel1Show = true; 125 126 MyUtils.startAnimIn(level2,200); 127 isLevel2Show = true; 128 } 129 130 } 131 132 133 134 135 }
其中要用到的工具类MyUtils(实现View旋转的方法工具),如下:
1 package com.himi.youkumenu; 2 3 import android.view.animation.RotateAnimation; 4 import android.widget.RelativeLayout; 5 6 public class MyUtils { 7 8 /** 9 * 菜单顺时针旋转离开 10 * @param view 11 */ 12 public static void startAnimOut(RelativeLayout view) { 13 startAnimOut(view, 0); 14 } 15 16 17 /** 18 * 菜单顺时针旋转进入 19 * @param view 20 */ 21 public static void startAnimIn(RelativeLayout view) { 22 startAnimIn(view,0); 23 } 24 25 /** 26 * 让指定的view延时执行旋转离开的画面 27 * @param view 28 * @param offset 延时时间 29 */ 30 public static void startAnimOut(RelativeLayout view, long offset) { 31 /** 32 * 默认圆心为view的左上角 33 * 水平向右为 0度 34 * 顺时针旋转度数增加 35 * 顺时针旋转离开度数变化是:0 ~ 180 36 */ 37 RotateAnimation animation = new RotateAnimation(0, 180, view.getWidth()/2, view.getHeight()); 38 animation.setDuration(500);//设置运行的时间 39 animation.setFillAfter(true);//动画执行完了之后,保持最后的状态 40 animation.setStartOffset(offset);//设置延时执行的时间参数 41 view.startAnimation(animation);//上面是设置动画效果参数,传入到view的方法startAnimation()方法. 42 } 43 44 /** 45 * 让指定的view延时执行旋转进入的画面 46 * @param view 47 * @param offset 延时时间 48 */ 49 50 public static void startAnimIn(RelativeLayout view, long offset) { 51 /** 52 * 默认圆心为view的左上角 53 * 水平向右为 0度 54 * 顺时针旋转度数增加 55 * 顺时针旋转离开度数变化是:180 ~ 360 56 */ 57 RotateAnimation animation = new RotateAnimation(180, 360, view.getWidth()/2, view.getHeight()); 58 animation.setDuration(500);//设置运行的时间 59 animation.setFillAfter(true);//动画执行完了之后,保持最后的状态 60 animation.setStartOffset(offset); 61 view.startAnimation(animation); 62 63 } 64 65 }
(7)部署程序到模拟器上,如下: