自定义控件学习之:追溯以前的优酷菜单

本文详细介绍了优酷菜单布局的实现方法,包括三个圆环的创建、图标显示与隐藏的逻辑处理,以及利用动画实现菜单的展开与收起效果。同时,通过设置延迟动画和监听手机menu按键来实现更流畅的用户体验。最后,修复了点击布局空白处导致菜单意外显示的bug,确保了功能的完整性和稳定性。

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

优酷菜单布局的实现:
第一步:实现三个圆环(最里面的圆环,中间圆环,最外面的圆环)

<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" >

    <RelativeLayout
        android:id="@+id/level3"
        android:layout_width="280dp"
        android:layout_height="140dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3" >
    </RelativeLayout>
 
    <RelativeLayout
        android:id="@+id/level2"
        android:layout_width="180dp"
        android:layout_height="90dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2" >
    </RelativeLayout>
    
    <RelativeLayout
        android:id="@+id/level1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1" >
    </RelativeLayout>
</RelativeLayout>

第二步:实现三个圆环里面的图标

<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" >

    <RelativeLayout
        android:id="@+id/level3"
        android:layout_width="280dp"
        android:layout_height="140dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3" >
        
           <ImageView 
               android:id="@+id/channel1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/channel1"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="10dp"
            android:layout_marginBottom="10dp"
            />
           
           <ImageView 
              android:id="@+id/channel2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/channel2"
            android:layout_above="@id/channel1"
         	android:layout_alignLeft="@id/channel1"
         	android:layout_marginLeft="20dp"
         	android:layout_marginBottom="10dp"
            />
           
           <ImageView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_above="@+id/channel2"
               android:layout_alignLeft="@+id/channel2"
               android:layout_marginBottom="8dp"
               android:layout_marginLeft="35dp"
               android:background="@drawable/channel3" />
           
           <ImageView
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_centerHorizontal="true"
               android:background="@drawable/channel4" 
               android:layout_marginTop="6dp"/>
           
           <ImageView
               android:id="@+id/channel7"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:background="@drawable/channel7" 
               android:layout_alignParentBottom="true"
               android:layout_alignParentRight="true"
               android:layout_marginRight="10dp"
               android:layout_marginBottom="10dp"
               />
           
           <ImageView
               android:id="@+id/channel6"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_above="@id/channel7"
               android:layout_alignRight="@id/channel7"
               android:layout_marginBottom="10dp"
               android:layout_marginRight="20dp"
               android:background="@drawable/channel6" />
           
           <ImageView
               android:id="@+id/channel5"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_above="@id/channel6"
               android:layout_alignRight="@id/channel6"
               android:layout_marginBottom="8dp"
               android:layout_marginRight="35dp"
               android:background="@drawable/channel5" />
          
    </RelativeLayout>
 
    
    <RelativeLayout
        android:id="@+id/level2"
        android:layout_width="180dp"
        android:layout_height="90dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2" >
        
           <ImageView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/icon_search"
            android:layout_margin="10dp"
            android:layout_alignParentBottom="true"
            />
           
           <ImageView
               android:id="@+id/icon_menu"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_centerHorizontal="true"
               android:layout_marginTop="5dp"
               android:background="@drawable/icon_menu" />
           
           <ImageView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/icon_myyouku"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_margin="10dp"
            />
        
    </RelativeLayout>
      
    <RelativeLayout
        android:id="@+id/level1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1" >

        <ImageView
            android:id="@+id/icon_home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@drawable/icon_home" />

    </RelativeLayout>
</RelativeLayout>

优酷代码实现:
旋转原理图分析:

第一步:二级,三级菜单的显示和隐藏


MainActivity.java
package com.example.youkumenu;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends Activity implements OnClickListener {

	private RelativeLayout level1, level2, level3;
	private ImageView icon_home, icon_menu;
	/** 判断三级菜单是否显示 true显示 false隐藏 */
	private boolean isLevel3Show = true;
	/** 判断二级菜单是否显示 true显示 false隐藏 */
	private boolean isLevel2Show = true;
	/** 判断一级菜单是否显示 true显示 false隐藏 */
	private boolean isLevel1Show = true;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 初始化空间
		level1 = (RelativeLayout) findViewById(R.id.level1);
		level2 = (RelativeLayout) findViewById(R.id.level2);
		level3 = (RelativeLayout) findViewById(R.id.level3);
		icon_home = (ImageView) findViewById(R.id.icon_home);
		icon_menu = (ImageView) findViewById(R.id.icon_menu);
		// 设置主页与菜单按钮的监听事件
		icon_home.setOnClickListener(this);
		icon_menu.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.icon_menu://响应menu图标的监听事件
			if(isLevel3Show){
				//隐藏三级菜单
				Tools.hiddenView(level3);
				isLevel3Show = false;
			}else{
				//显示三级菜单
				Tools.showView(level3);
				isLevel3Show = true;
			}
			break;
		case R.id.icon_home://响应home图标的监听事件
			if(isLevel2Show){
				//如果二级菜单是显示状态,那么隐藏二级菜单
				Tools.hiddenView(level2);
				isLevel2Show = false;
				//同时判断,三级菜单的状态,如果是显示,同样也隐藏三级菜单
				if(isLevel3Show){
					Tools.hiddenView(level3);
					isLevel3Show = false;
				}
			}else{
				//如果二级菜单是隐藏状态,那么显示二级菜单
				Tools.showView(level2);
				isLevel2Show = true;
			}
			break;
		}

	}
}
Tools.java:
package com.example.youkumenu;

import android.view.View;
import android.view.animation.RotateAnimation;
public class Tools {

	public static void showView(View view) {
		RotateAnimation ra = new RotateAnimation(180,360, view.getWidth()/2, view.getHeight());
		//设置动画的运行时间
		ra.setDuration(500);
		//动画执行完后,保持现有的状态
		ra.setFillAfter(true);
		//让view执行动画
		view.startAnimation(ra);
		
	}
	public static void hiddenView(View view) {
		/**
		 * RotateAnimation 中的四个参数:
		 * fromDegrees 从多少度
		 * toDegrees 到多少度
		 * pivotX 中心点的x 坐标
		 * pivotY 中心点的Y坐标
		 */
		RotateAnimation ra = new RotateAnimation(0, 180, view.getWidth()/2, view.getHeight());
		//设置动画的运行时间
		ra.setDuration(500);
		//动画执行完后,保持现有的状态
		ra.setFillAfter(true);
		//让view执行动画
		view.startAnimation(ra);
		
	}

}
第二步:设置延迟动画setStartOffset()方法和代码重构

Tools.java
package com.example.youkumenu;

import android.view.View;
import android.view.animation.RotateAnimation;
public class Tools {

	public static void showView(View view) {
		showView(view, 0);
	}

	public static void hiddenView(View view) {
		hiddenView(view, 0);

	}
	public static void hiddenView(View view, int startOffset) {
		/**
		 * RotateAnimation 中的四个参数:
		 * fromDegrees 从多少度 
		 * toDegrees 到多少度
		 * pivotX 中心点的x坐标
		 * pivotY 中心点的Y坐标
		 */
		RotateAnimation ra = new RotateAnimation(0, 180, view.getWidth() / 2,
				view.getHeight());
		// 设置动画的运行时间
		ra.setDuration(500);
		// 动画执行完后,保持现有的状态
		ra.setFillAfter(true);
		// 设置动画执行的延时时间
		ra.setStartOffset(startOffset);
		// 让view执行动画
		view.startAnimation(ra);
	}

	public static void showView(View view, int startOffset) {
		RotateAnimation ra = new RotateAnimation(180, 360, view.getWidth() / 2,
				view.getHeight());
		// 设置动画的运行时间
		ra.setDuration(500);
		// 动画执行完后,保持现有的状态
		ra.setFillAfter(true);
		// 设置动画执行的延时时间
		ra.setStartOffset(startOffset);
		// 让view执行动画
		view.startAnimation(ra);
	}

}
第三步:监听手机menu按键实现菜单的隐藏和显示


MainActivity.java:
package com.example.youkumenu;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends Activity implements OnClickListener {

	private RelativeLayout level1, level2, level3;
	private ImageView icon_home, icon_menu;
	/** 判断三级菜单是否显示 true显示 false隐藏 */
	private boolean isLevel3Show = true;
	/** 判断二级菜单是否显示 true显示 false隐藏 */
	private boolean isLevel2Show = true;
	/** 判断一级菜单是否显示 true显示 false隐藏 */
	private boolean isLevel1Show = true;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 初始化空间
		level1 = (RelativeLayout) findViewById(R.id.level1);
		level2 = (RelativeLayout) findViewById(R.id.level2);
		level3 = (RelativeLayout) findViewById(R.id.level3);
		icon_home = (ImageView) findViewById(R.id.icon_home);
		icon_menu = (ImageView) findViewById(R.id.icon_menu);
		// 设置主页与菜单按钮的监听事件
		icon_home.setOnClickListener(this);
		icon_menu.setOnClickListener(this);
	}
	/**
	 * 当点击手机按键的时候,触发该方法
	 * keyCode点击按键代表的值
	 * event按键事件
	 */
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		//判断是否点击menu按钮
		if(keyCode == KeyEvent.KEYCODE_MENU){
			//判断一级菜单
			//如果是隐藏状态,那么就显示一级菜单和二级菜单
			if(!isLevel1Show){
				Tools.showView(level1);
				isLevel1Show = true;
				//同时显示二级菜单
				Tools.showView(level2,200);
				isLevel2Show = true;
			}else{
				//如果一级菜单是显示状态
				//隐藏一级菜单 同时判断 ,隐藏二,三级菜单
				Tools.hiddenView(level1);
				isLevel1Show = false;
				if(isLevel2Show){
					Tools.hiddenView(level2,200);
					isLevel2Show = false;
					if(isLevel3Show){
						Tools.hiddenView(level3, 300);
						isLevel3Show = false;
					}
				}
			}
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.icon_menu://响应menu图标的监听事件
			if(isLevel3Show){
				//隐藏三级菜单
				Tools.hiddenView(level3);
				isLevel3Show = false;
			}else{
				//显示三级菜单
				Tools.showView(level3);
				isLevel3Show = true;
			}
			break;
		case R.id.icon_home://响应home图标的监听事件
			if(isLevel2Show){
				//如果二级菜单是显示状态,那么隐藏二级菜单
				Tools.hiddenView(level2);
				isLevel2Show = false;
				//同时判断,三级菜单的状态,如果是显示,同样也隐藏三级菜单
				if(isLevel3Show){
					Tools.hiddenView(level3,500);
					isLevel3Show = false;
				}
			}else{
				//如果二级菜单是隐藏状态,那么显示二级菜单
				Tools.showView(level2);
				isLevel2Show = true;
			}
			break;
		}

	}
}
优酷效果图的整体完成和bug的修复:

仔细观察效果图:会发现一点点的小bug。当我们通过menu按键隐藏一二三级菜单的时候,我们点击布局的空白处,同样会出现某些级的菜单。我们这里修复这个bug

package com.example.youkumenu;

import android.view.View;
import android.view.ViewGroup;
import android.view.animation.RotateAnimation;

public class Tools {

	public static void showView(ViewGroup view) {
		showView(view, 0);
	}

	public static void hiddenView(ViewGroup view) {
		hiddenView(view, 0);

	}

	public static void hiddenView(ViewGroup view, int startOffset) {
		/**
		 * RotateAnimation 中的四个参数:
		 * fromDegrees 从多少度 
		 * toDegrees 到多少度
		 * pivotX 中心点的x坐标
		 * pivotY 中心点的Y坐标
		 */
		RotateAnimation ra = new RotateAnimation(0, 180, view.getWidth() / 2,
				view.getHeight());
		// 设置动画的运行时间
		ra.setDuration(500);
		// 动画执行完后,保持现有的状态
		ra.setFillAfter(true);
		// 设置动画执行的延时时间
		ra.setStartOffset(startOffset);
		// 让view执行动画
		view.startAnimation(ra);
		<span style="color:#cc33cc;">for (int i = 0; i < view.getChildCount(); i++) {
			View child = view.getChildAt(i);
			child.setVisibility(View.GONE);
		}</span>
	}

	public static void showView(ViewGroup view, int startOffset) {
		RotateAnimation ra = new RotateAnimation(180, 360, view.getWidth() / 2,
				view.getHeight());
		// 设置动画的运行时间
		ra.setDuration(500);
		// 动画执行完后,保持现有的状态
		ra.setFillAfter(true);
		// 设置动画执行的延时时间
		ra.setStartOffset(startOffset);
		// 让view执行动画
		view.startAnimation(ra);
		<span style="color:#cc33cc;">/**
		 * ViewGroup中的方法介绍:
		 * getChildCount()返回子View的数量
		 * getChildAt(i)获得指定小标的子view
		 */
		for (int i = 0; i < view.getChildCount(); i++) {
			View child = view.getChildAt(i);
			child.setVisibility(View.VISIBLE);
		}</span>
	}

}

整体运行效果:


源代码下载:

http://download.csdn.net/detail/btt2013/9311963


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上善若水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值