本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);
}