功能简述:
实现一个扇形的3级菜单,由内向外分别是一级菜单、二级菜单、三级菜单。
功能:
1. 点击一级菜单时显示二级菜单,当点击二级菜单时,显示三级菜单。
2. 当点击屏幕上的一个按钮时,会隐藏所有的控件。再次点击时,会显示所有的控件。
效果如图:
,
此图是从网上找的。
菜单UI
主要思路是:全部使用相对布局,以实现图片的叠加。主要用到了 android:layout_alignParentBottom=”true”和android:layout_alignParentRight=”true”
以及设置margin距离。我这上面没有找到menu键,就添加了一个按钮,表示是menu键。
<?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"
tools:context="com.example.customview.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button"
android:id="@+id/button1"
/>
<!--第一级菜单-->
<RelativeLayout
android:id="@+id/rl_level1"
android:layout_width="100dp"
android:background="@drawable/level1"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true">
<ImageView
android:id="@+id/iv_home"
android:layout_width="wrap_content"
android:background="@drawable/icon_home"
android:layout_centerInParent="true"
android:layout_height="wrap_content" />
</RelativeLayout>
<!--第二级菜单-->
<RelativeLayout
android:id="@+id/rl_level2"
android:layout_width="180dp"
android:layout_height="90dp"
android:background="@drawable/level2"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="10dp"
android:layout_marginBottom="10dp"
android:background="@drawable/icon_search"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:background="@drawable/icon_myyouku"/>
<ImageView
android:id="@+id/iv_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="@drawable/icon_menu"
/>
</RelativeLayout>
<!--第三级菜单-->
<RelativeLayout
android:id="@+id/rl_level3"
android:layout_width="280dp"
android:background="@drawable/level3"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_height="140dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="0dp"
android:layout_marginLeft="5dp"
android:background="@drawable/channel1"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel2"
android:layout_alignParentBottom="true"
android:layout_marginBottom="40dp"
android:layout_marginLeft="28dp"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel3"
android:layout_alignParentBottom="true"
android:layout_marginBottom="80dp"
android:layout_marginLeft="60dp"
/>
<!--这个是最中间的-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="@drawable/channel4"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="0dp"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
android:background="@drawable/channel5"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel6"
android:layout_alignParentBottom="true"
android:layout_marginBottom="40dp"
android:layout_alignParentRight="true"
android:layout_marginRight="28dp"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/channel7"
android:layout_alignParentBottom="true"
android:layout_marginBottom="80dp"
android:layout_alignParentRight="true"
android:layout_marginRight="60dp"
/>
</RelativeLayout>
</RelativeLayout>
控制逻辑
这个地方比较常规:
package com.example.customview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
private ImageView ivHome;
private ImageView ivMenu;
private Button button;
private boolean isShowLevel2 = true;//是否显示2级菜单
private boolean isShowLevel3 = true;//是否显示3级菜单
private boolean isShowMenu = true;//是否显示整个菜单,包括1级,2级,3级的菜单
private RelativeLayout rlLevel1;
private RelativeLayout rlLevel2;
private RelativeLayout rlLevel3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
initListener();
}
//绑定监听器
private void initListener() {
ivHome.setOnClickListener(this);
ivMenu.setOnClickListener(this);
button.setOnClickListener(this);
}
//初始化视图
private void initView() {
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button1);
ivHome = (ImageView) findViewById(R.id.iv_home);
ivMenu = (ImageView) findViewById(R.id.iv_menu);
rlLevel1 = (RelativeLayout) findViewById(R.id.rl_level1);
rlLevel2 = (RelativeLayout) findViewById(R.id.rl_level2);
rlLevel3 = (RelativeLayout) findViewById(R.id.rl_level3);
}
//绑定事件
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_home:
if (AnimUtil.animCount != 0) {
return;
}
if (isShowLevel2) {
Log.d(TAG, "onClick: iv_home 隐藏");
//先隐藏三级菜单,之后再隐藏二级菜单
int animaDelay = 0;
if (isShowLevel3) {
AnimUtil.closeMenu(rlLevel3, animaDelay);
animaDelay += 200;
isShowLevel3 = false;
}
AnimUtil.closeMenu(rlLevel2, animaDelay);
} else {
Log.d(TAG, "onClick: iv_home 显示");
AnimUtil.showMenu(rlLevel2,0);
}
isShowLevel2 = !isShowLevel2;
break;
case R.id.iv_menu:
if (AnimUtil.animCount != 0) {
return;
}
if (isShowLevel3) {
AnimUtil.closeMenu(rlLevel3, 0);
} else {
AnimUtil.showMenu(rlLevel3,0);
}
isShowLevel3 = !isShowLevel3;
break;
case R.id.button1:
if(isShowMenu){
int animDelay = 0;
if(isShowLevel3){
AnimUtil.closeMenu(rlLevel3,animDelay);
animDelay += 200;
isShowLevel3 = false;
}
if (isShowLevel2){
AnimUtil.closeMenu(rlLevel2,animDelay);
animDelay+=200;
isShowLevel2 = false;
}
AnimUtil.closeMenu(rlLevel1,animDelay);
}else{
int animDelay = 0;
AnimUtil.showMenu(rlLevel1,animDelay);
animDelay += 200;
AnimUtil.showMenu(rlLevel2,animDelay);
animDelay += 200;
isShowLevel2 = true;
AnimUtil.showMenu(rlLevel3,animDelay);
isShowLevel3 = true;
}
isShowMenu = !isShowMenu;
break;
}
}
}
动画播放工具类
public class AnimUtil {
// 问题1:为了解决快速连续双击按钮时动画播放不完,出现的抖动的效果,使用一个计数器animCount标记动画开始个数,
// 开始一个计数器加1,播放完一个计数器减1。在Activity中调用时,判断animCount的个数
public static int animCount = 0;
public static void closeMenu(RelativeLayout rl,long startOffset) {
//让父控件内部的所有子控件禁用
for (int i = 0; i < rl.getChildCount(); i++) {
View v = rl.getChildAt(i);
v.setEnabled(false);
}
//逆时针旋转180度
RotateAnimation animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 1.0f);
animation.setDuration(500);
// 动画结束后保存原来的状态
animation.setFillAfter(true);
animation.setStartOffset(startOffset);
animation.setAnimationListener(new MyAnimationListener());
rl.startAnimation(animation);
}
public static void showMenu(RelativeLayout relativeLayout, long startOffset) {
//让父控件内的所有子控件启用
for (int i = 0; i < relativeLayout.getChildCount(); i++) {
View v = relativeLayout.getChildAt(i);
v.setEnabled(true);
}
//顺时针旋转180度
RotateAnimation animation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 1.0f);
animation.setDuration(500);
//动画结束后保存原来的状态
animation.setFillAfter(true);
animation.setStartOffset(startOffset);
animation.setAnimationListener(new MyAnimationListener());
relativeLayout.startAnimation(animation);
}
// 自定义动画监听器
static class MyAnimationListener implements Animation.AnimationListener{
@Override
public void onAnimationStart(Animation animation) {
animCount++;
}
@Override
public void onAnimationEnd(Animation animation) {
animCount--;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
}
}
难点:
- 当点击第一级菜单时隐藏了二级菜单,但是点击空白区域,还是可以响应用户的输入。解决办法,在closeMenu()函数中将该布局的所有自控件将其设置为不可用。同时在showMenum()中将所有子控件设置为可用。
- 当用户快速连续点击时,会出现隐藏动画没有执行完,就开始执行显示动画。通过在AnimUtil中,设置一个计数器animCount,当播放一个动画时,animCount++,播放完毕,animCount–,在MainActivity中,判断animCount是否等于0,来判断动画是否播放结束。