Android自定义Menu ------仿优酷Android客户端Menu样式的实现

                     

                   先上一下效果图:

                                           

 

                                    这个可以转动的Menu样式 源于优酷网客户端中 之前已经有人实现过了 在此基础上整理修改了一下代码增加了按Menu键位弹出和隐藏的功能,

         其中旋转和弹出特效通过使用 Animation动画实现 以控件自身纵坐标最下点 横坐标的中间点为中心 使用旋转动画(RotateAnimation)即可实现Menu的旋转特效. 

 

            下面是主要实现代码:

                                layout/rotate_menu.xml      //整个menu的布局文件

             

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id = "@+id/rotate_menu"
    android:layout_width="280dp"
    android:layout_height="140dp" 
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true">
    <RelativeLayout
        android:id="@+id/relate_level3"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3" >

        <ImageButton
            android:id="@+id/c1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="6dip"
            android:layout_marginLeft="12dip"
            android:background="@drawable/channel1" />

        <ImageButton
            android:id="@+id/c2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/c1"
            android:layout_marginBottom="12dip"
            android:layout_marginLeft="28dip"
            android:background="@drawable/channel2" />

        <ImageButton
            android:id="@+id/c3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/c2"
            android:layout_marginBottom="8dip"
            android:layout_marginLeft="6dip"
            android:layout_toRightOf="@+id/c2"
            android:background="@drawable/channel3" />

        <ImageButton
            android:id="@+id/c4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_margin="6dip"
            android:background="@drawable/channel4" />

        <ImageButton
            android:id="@+id/c5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/c6"
            android:layout_marginBottom="8dip"
            android:layout_marginRight="6dip"
            android:layout_toLeftOf="@+id/c6"
            android:background="@drawable/channel5" />

        <ImageButton
            android:id="@+id/c6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/c7"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="12dip"
            android:layout_marginRight="28dip"
            android:background="@drawable/channel6" />

        <ImageButton
            android:id="@+id/c7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="6dip"
            android:layout_marginRight="12dip"
            android:background="@drawable/channel7" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/relate_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/menu"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_margin="6dip"
            android:background="@drawable/icon_menu" />

        <ImageButton
            android:id="@+id/search"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_margin="10dip"
            android:background="@drawable/icon_search" />

        <ImageButton
            android:id="@+id/myyouku"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_margin="10dip"
            android:background="@drawable/icon_myyouku" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/relate_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/home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="10dp"
            android:background="@drawable/icon_home" />
    </RelativeLayout>

</RelativeLayout>

              每一圈 Menu使用一个RelativeLayout作为父布局 menu按钮通过在RelativeLayout中互相设置相对关系实现环形排列的效果

          下面是实现Menu动画设定和旋转弹出Menu逻辑的代码:  RotateMenuController.java

import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageButton;

public class RotateMenuController implements View.OnClickListener{
	
	private ViewGroup groupLevel1;
	private ViewGroup groupLevel2;
	private ViewGroup groupLevel3;
	
	private ImageButton menuButton;
	private ImageButton homeButton;
	
	private boolean isLevel1Show = true;
	private boolean isLevel2Show = true;
	private boolean isLevel3Show = true;
	
	public static final long DEF_ANIM_DURATION = 400;
	public static final long DEF_ANIM_START_OFFSET = 300;
	
	public RotateMenuController(Activity activity){
		View v = activity.findViewById(R.id.rotate_menu);
		
		if(v == null){
			throw new IllegalArgumentException(
					"can not inflate rotate menu layout form current activity");
		}
		
		groupLevel1 = (ViewGroup) v.findViewById(R.id.relate_level1);
		groupLevel2 = (ViewGroup) v.findViewById(R.id.relate_level2);
		groupLevel3 = (ViewGroup) v.findViewById(R.id.relate_level3);
		
		menuButton = (ImageButton) v.findViewById(R.id.menu);
		homeButton = (ImageButton) v.findViewById(R.id.home);
		
		menuButton.setOnClickListener(this);
		homeButton.setOnClickListener(this);
		
		//switchMenu();
	}
	
	public void switchMenu(){
		if(isLevel1Show){
			if(isLevel3Show && isLevel2Show){
				rotateMenuOut(groupLevel3, DEF_ANIM_DURATION, 0, level3OutListener);
				rotateMenuOut(
						groupLevel2, DEF_ANIM_DURATION, DEF_ANIM_START_OFFSET, level2OutListener);
				slideMenuOut(
						groupLevel1, DEF_ANIM_DURATION, DEF_ANIM_START_OFFSET + DEF_ANIM_DURATION, level1OutListener);
			}else if(isLevel2Show){
				rotateMenuOut(
						groupLevel2, DEF_ANIM_DURATION, 0, level2OutListener);
				slideMenuOut(
						groupLevel1, DEF_ANIM_DURATION, DEF_ANIM_START_OFFSET, level1OutListener);
			}else{
				slideMenuOut(
						groupLevel1, DEF_ANIM_DURATION, 0, level1OutListener);
			}
		}else{
			slideMenuIn(groupLevel1, DEF_ANIM_DURATION, 0, level1InListener);
			
		}
	}
	
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.menu:
		{
			if(isLevel3Show){
				rotateMenuOut(
						groupLevel3, DEF_ANIM_DURATION, 0, level3OutListener);
			}else{
				rotateMenuIn(
						groupLevel3, DEF_ANIM_DURATION, 0, level3InListener);
			}
		}
			break;
		case R.id.home:
		{
			if(isLevel2Show){
				if(isLevel3Show){
					rotateMenuOut(
							groupLevel3,DEF_ANIM_DURATION, 0, level3OutListener);
					rotateMenuOut(
							groupLevel2, DEF_ANIM_DURATION, DEF_ANIM_START_OFFSET, level2OutListener);
				}else{
					rotateMenuOut(
							groupLevel2, DEF_ANIM_DURATION, 0, level2OutListener);
				}
				
			}else{
				rotateMenuIn(
						groupLevel2, DEF_ANIM_DURATION, 0, level2InListener);
			}
		}
			break;
		}
	}
	
	private Animation.AnimationListener level3InListener = new Animation.AnimationListener() {
		
		@Override
		public void onAnimationStart(Animation animation) {
			menuButton.setClickable(false);
			activeMenus(groupLevel3);
		}
		
		@Override
		public void onAnimationRepeat(Animation animation) {
		}
		
		@Override
		public void onAnimationEnd(Animation animation) {
			isLevel3Show = true;
			menuButton.setClickable(true);
		}
	};
	
	private Animation.AnimationListener level3OutListener = new Animation.AnimationListener() {
		
		@Override
		public void onAnimationStart(Animation animation) {
			menuButton.setClickable(false);
		}
		
		@Override
		public void onAnimationRepeat(Animation animation) {
		}
		
		@Override
		public void onAnimationEnd(Animation animation) {
			isLevel3Show = false;
			menuButton.setClickable(true);
			lockMenus(groupLevel3);
		}
	};
	
	private Animation.AnimationListener level2InListener = new Animation.AnimationListener() {
		
		@Override
		public void onAnimationStart(Animation animation) {
			homeButton.setClickable(false);
			activeMenus(groupLevel2);
		}
		
		@Override
		public void onAnimationRepeat(Animation animation) {
		}
		
		@Override
		public void onAnimationEnd(Animation animation) {
			isLevel2Show = true;
			homeButton.setClickable(true);
		}
	};
	
	private Animation.AnimationListener level2OutListener = new Animation.AnimationListener() {
		
		@Override
		public void onAnimationStart(Animation animation) {
			homeButton.setClickable(false);
		}
		
		@Override
		public void onAnimationRepeat(Animation animation) {
		}
		
		@Override
		public void onAnimationEnd(Animation animation) {
			isLevel2Show = false;
			homeButton.setClickable(true);
			lockMenus(groupLevel2);
			
		}
	};
	
	private Animation.AnimationListener level1InListener = new Animation.AnimationListener() {
		
		@Override
		public void onAnimationStart(Animation animation) {
			activeMenus(groupLevel1);
		}
		
		@Override
		public void onAnimationRepeat(Animation animation) {
		}
		
		@Override
		public void onAnimationEnd(Animation animation) {
			isLevel1Show = true;
		}
	};
	
	private Animation.AnimationListener level1OutListener = new Animation.AnimationListener() {
		
		@Override
		public void onAnimationStart(Animation animation) {
		}
		
		@Override
		public void onAnimationRepeat(Animation animation) {
		}
		
		@Override
		public void onAnimationEnd(Animation animation) {
			isLevel1Show = false;
			lockMenus(groupLevel1);
		}
	};
	
	private void lockMenus(ViewGroup group){
		group.setVisibility(View.GONE);
		int childCount = group.getChildCount();
		for(int i=0; i<childCount; i++){
			group.getChildAt(i).setVisibility(View.GONE);
			group.getChildAt(i).setFocusable(false);
			group.getChildAt(i).setClickable(false);
		}
	}
	
	private void activeMenus(ViewGroup group){
		group.setVisibility(View.VISIBLE);
		int childCount = group.getChildCount();
		for(int i=0; i<childCount; i++){
			group.getChildAt(i).setVisibility(View.VISIBLE);
			group.getChildAt(i).setFocusable(true);
			group.getChildAt(i).setClickable(true);
		}
	}
	
              	
	private void rotateMenuIn(ViewGroup group, long durationMills, long startOffset, Animation.AnimationListener listener){
		RotateAnimation rotateInAnim = new RotateAnimation(
			-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 1.0f);
		rotateInAnim.setFillAfter(true);
		rotateInAnim.setStartOffset(startOffset);
		rotateInAnim.setDuration(durationMills);
		rotateInAnim.setAnimationListener(listener);
		group.startAnimation(rotateInAnim);
	}

	private void rotateMenuOut(ViewGroup group, long durationMills, long startOffset, Animation.AnimationListener listener){
		RotateAnimation rotateOutAnim = new RotateAnimation(
			0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 1.0f);
		rotateOutAnim.setFillAfter(true);
		rotateOutAnim.setStartOffset(startOffset);
		rotateOutAnim.setDuration(durationMills);
		rotateOutAnim.setAnimationListener(listener);
		group.startAnimation(rotateOutAnim);
	}

	private void slideMenuIn(ViewGroup group, long durationMills, long startOffset, Animation.AnimationListener listener){
		TranslateAnimation slideInAnim = new TranslateAnimation(
			Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, 
			Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0.0f);
		slideInAnim.setFillAfter(true);
		slideInAnim.setStartOffset(startOffset);
		slideInAnim.setDuration(durationMills);
		slideInAnim.setAnimationListener(listener);
		group.startAnimation(slideInAnim);
	}

	private void slideMenuOut(ViewGroup group, long durationMills, long startOffset, Animation.AnimationListener listener){
		TranslateAnimation slideOutAnim = new TranslateAnimation(
			Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, 
			Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f);
		slideOutAnim.setFillAfter(true);
		slideOutAnim.setStartOffset(startOffset);
		slideOutAnim.setDuration(durationMills);
		slideOutAnim.setAnimationListener(listener);
		group.startAnimation(slideOutAnim);
	}	
}

                          

  其中 动画定义函数:

  /**
  * menu 弹出屏幕动画定义  以自身为参照(Animation.Animation.RELATIVE_TO_SELF 参数)  向下移动自身高度的100% (1.0f 参数) 
  */
 

private void slideMenuOut(ViewGroup group, long durationMills, long startOffset, Animation.AnimationListener listener){
		TranslateAnimation slideOutAnim = new TranslateAnimation(
			Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, 
			Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f);
		slideOutAnim.setFillAfter(true);
		slideOutAnim.setStartOffset(startOffset);
		slideOutAnim.setDuration(durationMills);
		slideOutAnim.setAnimationListener(listener);
		group.startAnimation(slideOutAnim);
	}

 

/**
  * menu 进入屏幕动画定义 以自身为参照(Animation.Animation.RELATIVE_TO_SELF 参数) 向上移动自身高度的100%(1.0f 参数)
  * 即弹出屏幕动画的反向执行
  */

 

private void slideMenuIn(ViewGroup group, long durationMills, long startOffset, Animation.AnimationListener listener){
		TranslateAnimation slideInAnim = new TranslateAnimation(
			Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, 
			Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0.0f);
		slideInAnim.setFillAfter(true);
		slideInAnim.setStartOffset(startOffset);
		slideInAnim.setDuration(durationMills);
		slideInAnim.setAnimationListener(listener);
		group.startAnimation(slideInAnim);
	}
	

 

   /**
  * menu 旋出动画定义 以自身为参照(Animation.Animation.RELATIVE_TO_SELF 参数) 从0度旋转至-180度
  */

 

private void rotateMenuOut(ViewGroup group, long durationMills, long startOffset, Animation.AnimationListener listener){
		RotateAnimation rotateOutAnim = new RotateAnimation(
			0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 1.0f);
		rotateOutAnim.setFillAfter(true);
		rotateOutAnim.setStartOffset(startOffset);
		rotateOutAnim.setDuration(durationMills);
		rotateOutAnim.setAnimationListener(listener);
		group.startAnimation(rotateOutAnim);
	}


 

 /**
  * menu 旋入动画定义 以自身为参照(Animation.Animation.RELATIVE_TO_SELF 参数) 从-180度旋转至0度
  * 即旋出动画的反向执行
  */

 

private void rotateMenuIn(ViewGroup group, long durationMills, long startOffset, Animation.AnimationListener listener){
		RotateAnimation rotateInAnim = new RotateAnimation(
			-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 1.0f);
		rotateInAnim.setFillAfter(true);
		rotateInAnim.setStartOffset(startOffset);
		rotateInAnim.setDuration(durationMills);
		rotateInAnim.setAnimationListener(listener);
		group.startAnimation(rotateInAnim);
	}


 setFillafter(boolean)   表示动画结束后是否停留在动画的最后位置 (为实现效果 必须设置为true)

setDuration(long); 设置执行一次的持续时间 (可以自行按需要调节)

setStartOffset(long) : 设置动画启动时间延迟 (可以自行按需要调节)

 

menu的控件,动画和顺序逻辑都封装在 RotateMenuController中了 在Activity中创建此实例并调用switchMenu()函数实现弹入弹出屏幕即可

public class MainActivity extends Activity {	
	private RotateMenuController menuController;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		menuController = new RotateMenuController(this);
		
		
	}

	public boolean onMenuOpened(int featureId, Menu menu) {
		return false;
	};
	
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if(keyCode == KeyEvent.KEYCODE_MENU){
						
			menuController.switchMenu();
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}
}


 

原文参考地址 http://www.eoeandroid.com/forum.php?mod=viewthread&tid=236310

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值