自定义组合控件之——旋转的菜单(老优酷菜单)

本文介绍了一个基于Android的应用中实现多级菜单的旋转动画效果的方法。文章详细解释了如何使用补间动画来控制不同级别的菜单显示与隐藏,并展示了具体的XML布局及Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、布局效果图如图所示:


要实现的逻辑功能:

点击menu,控制三级菜单的显示:

如果当前三级菜单显示,就把它转出去(逆时针180)。如果不显示,就转出来三级菜单(顺时针180)。

点击home,控制二级菜单的显示:

如果三级菜单不显示,二级菜单显示直接转出去二级菜单:

如果三级菜单不显示,二级菜单不显示直接转出来二级菜单:

如果当前三级菜单显示,就先把它转出去,间隔一段时间二级菜单也转出去;

点击手机键盘上的menu,控制所有菜单的显示:

如果,当前有菜单显示,则按照三,二,一的顺序,互相间隔一定的时间顺序转出去。

如果,当前没有菜单显示,则按照一、二、三的顺序,互相间隔一定的时间顺序转出来。

二、xml布局:

layout_marginTop/Bottomlayout_marginLeft/Right控制组件的位置

<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=".MainActivity" >
    <RelativeLayout
        android:id="@+id/first_menu"
        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/second_menu"
        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:layout_marginTop="5dp"
            android:src="@drawable/icon_menu" />
        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="10dp"
            android:layout_marginBottom="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="10dp"
            android:layout_marginBottom="5dp"
            android:background="@null"
            android:src="@drawable/icon_myyouku" />
    </RelativeLayout>
    <RelativeLayout
        android:id="@+id/third_menu"
        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_marginLeft="10dp"
            android:layout_marginBottom="5dp"
            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="60dp"
            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="25dp"
            android:background="@null"
            android:src="@drawable/channel3" />
        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:background="@null"
            android:layout_marginTop="5dp"
            android:src="@drawable/channel4" />     
        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:background="@null"
            android:layout_marginRight="30dp"
            android:layout_marginTop="60dp"
            android:src="@drawable/channel5" /> 
        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="65dp"
            android:layout_marginTop="25dp"
            android:layout_alignParentRight="true"
            android:background="@null"
            android:src="@drawable/channel6" />
        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginRight="10dp"
            android:layout_marginBottom="5dp"
            android:background="@null"
            android:src="@drawable/channel7" />
    </RelativeLayout>
</RelativeLayout>

三、旋转动画的逻辑,使用补间动画旋转指定的菜单,并监听记录在旋转的菜单个数,当菜单被旋转出去的时候设置该菜单内的控件不可点击,旋转出来的时候可以点击。

public class AnimationUtils{
	// 正在运行的动画个数
	public static int runningAnimationCount = 0;
	
	public static void rotateOut(RelativeLayout layout,long delay){
		//旋转出去后,找到它的所有子view,禁用,防止layout隐藏之后在原来位置还可以响应点击事件
		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坐标点(指定旋转中心x值)
				Animation.RELATIVE_TO_SELF, 1.0f); // 相对的y坐标点(指定旋转中心y值)
		ra.setDuration(500);//设置旋转的时间
		ra.setFillAfter(true);//设置动画结束的时候,停留在结束的位置
		ra.setStartOffset(delay);//设置动画开始延时
		ra.setAnimationListener(new MyAnimationListener());//添加监听
		layout.startAnimation(ra);	
	}
	public static void rotateIn(RelativeLayout layout,long delay){
		//旋转进来后,找到它的所有子view,启用
		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, Animation.RELATIVE_TO_SELF, 1.0f);
		ra.setDuration(500);//设置旋转的时间
		ra.setFillAfter(true);//设置动画结束的时候,停留在结束的位置
		ra.setStartOffset(delay);//设置动画开始延时
		ra.setAnimationListener(new MyAnimationListener());//添加监听
		layout.startAnimation(ra);	
	}
	static class MyAnimationListener implements AnimationListener{
		@Override
		public void onAnimationEnd(Animation animation) {
              runningAnimationCount	--;		
		}
		@Override
		public void onAnimationRepeat(Animation animation) {
			// TODO Auto-generated method stub	
		}
		@Override
		public void onAnimationStart(Animation animation) {
			runningAnimationCount ++;
		}	
	}
}

四、

对相应的按钮设置监听事件,在没有菜单正在旋转的时候,开始响应,实现相应的业务逻辑。

public class MainActivity extends Activity implements OnClickListener {
	private RelativeLayout rl_level1;
	private RelativeLayout rl_level2;
	private RelativeLayout rl_level3;
	boolean isLevel3Display = true;
	boolean isLevel2Display = true;
	boolean isLevel1Display = true;
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.ib_home).setOnClickListener(this);
		findViewById(R.id.ib_menu).setOnClickListener(this);
		rl_level1 = (RelativeLayout) findViewById(R.id.first_menu);
		rl_level2 = (RelativeLayout) findViewById(R.id.second_menu);
		rl_level3 = (RelativeLayout) findViewById(R.id.third_menu);   
    }
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		//点击手机上的menu按钮执行的逻辑
		// keyCode 事件码
		//通过这个可以获取到事件码System.out.println("onKeyDown: " + keyCode);
		if(keyCode == KeyEvent.KEYCODE_MENU){
			if(AnimationUtils.runningAnimationCount > 0){
				// 当前有动画正在执行, 取消当前事件
				return true;
			}
			if(isLevel1Display){
				long delay = 0;
				// 隐藏三级菜单
				if(isLevel3Display){
					AnimationUtils.rotateOut(rl_level3, 0);
					isLevel3Display = false;
					delay += 200;
				}
				// 隐藏二级菜单
				if(isLevel2Display){
					AnimationUtils.rotateOut(rl_level2, delay);
					isLevel2Display = false;
					delay += 200;
				}
				// 隐藏一级菜单
				AnimationUtils.rotateOut(rl_level1, delay);
			}else {
				// 三级菜单全部依次转出来
				AnimationUtils.rotateIn(rl_level1, 0);
				AnimationUtils.rotateIn(rl_level2, 200);
				AnimationUtils.rotateIn(rl_level3, 400);
				isLevel3Display = true;
				isLevel2Display = true;
			}
			isLevel1Display = !isLevel1Display;
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}

	@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.rotateOut(rl_level3, 0);
					isLevel3Display = false;
					delay += 200;
				}
				// 如果二级菜单已经显示, 转出去
				AnimationUtils.rotateOut(rl_level2, delay);
			}else {
				// 如果二级菜单没有显示, 转出来
				AnimationUtils.rotateIn(rl_level2, 0);
			}
			isLevel2Display = !isLevel2Display;
			break;
		case R.id.ib_menu:
			if(isLevel3Display){
				// 如果三级菜单已经显示, 转出去
				AnimationUtils.rotateOut(rl_level3, 0);
			}else {
				// 如果三级菜单没有显示, 转出来
				AnimationUtils.rotateIn(rl_level3, 0);
			}
			isLevel3Display = !isLevel3Display;
			break;

		default:
			break;
		}
	} 
}

五、重要的事情写后边

测试很顺利啊,感冒了,涕流不止啊,就写到这儿吧!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值