先上一下效果图:
这个可以转动的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