去年的优酷HD版有过这样一种菜单,如下图:

应用打开之后,先是三个弧形的三级菜单,点击实体键menu之后,这三个菜单依次旋转退出,再点击实体键menu之后,一级菜单会旋转进入,点击一级菜单,二级菜单旋转进入,点击二级菜单的menu键,三级菜单旋转进入,再次点击二级菜单的旋转键,三级菜单又会旋转退出,这时再点击一级菜单,二级菜单退出,最后点击实体menu键,一级菜单退出。

总体来说实现这样的功能:

(1)点击实体menu键时,如果界面上有菜单显示,不管有几个,全部依次退出,如果界面上没有菜单显示,则显示一级菜单。

(2)点击一级菜单的home键时,如果此时界面只有一级菜单,则显示二级菜单,否则让除了一级菜单外的菜单全都依次退出。

(3)点击二级菜单的menu键时,如果三级菜单已经显示,则让它旋转退出,如果三级菜单未显示则让它旋转进入。

好了,今天我们主要实现上述效果。

先来看布局文件

<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="com.example.customwidget.MainActivity" > <RelativeLayout
android:id="@+id/menu_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/level1_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginBottom="10dp"
android:background="@drawable/icon_home"
android:onClick="myClick" />
</RelativeLayout> <RelativeLayout
android:id="@+id/menu_level2"
android:layout_width="200dp"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/level2" > <ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="15dp"
android:background="@drawable/icon_search" /> <ImageButton
android:id="@+id/level2_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="7dp"
android:background="@drawable/icon_menu"
android:onClick="myClick" /> <ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="10dp"
android:layout_marginRight="15dp"
android:background="@drawable/icon_myyouku" />
</RelativeLayout> <RelativeLayout
android:id="@+id/menu_level3"
android:layout_width="320dp"
android:layout_height="162dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/level3" > <ImageButton
android:id="@+id/level3_channel1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="12dp"
android:background="@drawable/channel1" /> <ImageButton
android:id="@+id/level3_channel2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel1"
android:layout_marginBottom="17dp"
android:layout_marginLeft="-5dp"
android:layout_toRightOf="@id/level3_channel1"
android:background="@drawable/channel2" /> <ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel2"
android:layout_marginBottom="15dp"
android:layout_marginLeft="13dp"
android:layout_toRightOf="@id/level3_channel2"
android:background="@drawable/channel3" /> <ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:background="@drawable/channel4" /> <ImageButton
android:id="@+id/level3_channel7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="10dp"
android:layout_marginRight="12dp"
android:background="@drawable/channel7" /> <ImageButton
android:id="@+id/level3_channel6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel7"
android:layout_marginBottom="17dp"
android:layout_marginRight="-5dp"
android:layout_toLeftOf="@id/level3_channel7"
android:background="@drawable/channel6" /> <ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/level3_channel6"
android:layout_marginBottom="15dp"
android:layout_marginRight="13dp"
android:layout_toLeftOf="@id/level3_channel6"
android:background="@drawable/channel5" />
</RelativeLayout> </RelativeLayout>

这里是一个相对布局中嵌套了三个相对布局,嵌套的第一个相对布局负责显示一级菜单,嵌套的第二个相对布局负责显示二级菜单,嵌套的第三个相对布局负责显示三级菜单。三个不同层次的菜单的背景都是弧形。我们通过指定具体的宽高来使三个层次的菜单具有不同的大小。

效果如下:

再看看MainActivity.java

/**
* 模仿优酷菜单
* 2015年5月19日
*/
public class MainActivity extends Activity { //分别拿到不同等级的菜单
private RelativeLayout lv1;
private RelativeLayout lv2;
private RelativeLayout lv3;
private Animation animation;
//各级菜单是否显示,默认全都显示
private boolean isDisplaylv1 = true;
private boolean isDisplaylv2 = true;
private boolean isDisplaylv3 = true;
//动画是否正在执行,默认动画没有执行
private boolean isAnimationRunning = false; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv1 = (RelativeLayout) this.findViewById(R.id.menu_level1);
lv2 = (RelativeLayout) this.findViewById(R.id.menu_level2);
lv3 = (RelativeLayout) this.findViewById(R.id.menu_level3);
} @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//如果动画正在执行,则不处理此事件
if (isAnimationRunning)
return super.onKeyDown(keyCode, event);
//如果点击的是菜单键
if (keyCode == KeyEvent.KEYCODE_MENU) {
//如果一级菜单已经显示,判断二级菜单是否显示
if (isDisplaylv1) {
//设置动画启动延迟时间
int startOffset = 0;
//如果二级菜单已经显示,判断三级菜单是否显示,然后退出二级菜单
if (isDisplaylv2) {
if (isDisplaylv3) {
//如果三级菜单已经显示,执行退出动画
exitAnimation(lv3, startOffset);
//三级菜单退出动画执行完毕之后,动画的启动时间延迟500ms
startOffset += 500;
isDisplaylv3 = !isDisplaylv3;
}
//二级菜单退出,此时startOffset=500,即动画启动时间延迟500ms
exitAnimation(lv2, startOffset);
//二级菜单退出动画执行完毕之后,动画的启动时间延迟500ms
startOffset += 500;
isDisplaylv2 = !isDisplaylv2;
}
//一级菜单退出,此时startOffset=1000,即动画启动时间延迟1000ms
exitAnimation(lv1, startOffset);
//如果一级菜单未显示,则一级菜单进入
} else {
enterAnimation(lv1);
}
isDisplaylv1 = !isDisplaylv1;
return true;
}
return super.onKeyDown(keyCode, event);
} public void myClick(View v) {
//如果动画正在执行,则不处理此事件
if (isAnimationRunning)
return;
switch (v.getId()) {
/**
* 当点击二级菜单的menu时,如果三级菜单已经显示,则执行退出动画,
* 否则执行进入动画
*/
case R.id.level2_menu:
if (isDisplaylv3) {
exitAnimation(lv3, 0);
} else {
enterAnimation(lv3);
}
isDisplaylv3 = !isDisplaylv3;
break;
case R.id.level1_home:
// 如果二级菜单已经显示,再判断三级菜单是否显示
if (isDisplaylv2) {
//通过设置动画启动延迟时间,来实现动画依次退出效果
int startOffset = 0;
// 如果三级菜单也显示了,则让他们依次退出
if (isDisplaylv3) {
exitAnimation(lv3, startOffset);
startOffset = 700;
isDisplaylv3 = !isDisplaylv3;
}
exitAnimation(lv2, startOffset);
isDisplaylv2 = !isDisplaylv2;
// 如果二级菜单没有显示,就让二级菜单显示出来
} else {
enterAnimation(lv2);
isDisplaylv2 = !isDisplaylv2;
}
break;
}
} /**
* 退出动画
* @param layout 执行动画的布局文件
* @param startOffset 动画启动的延迟时间
*/
public void exitAnimation(RelativeLayout layout, long startOffset) {
animation = AnimationUtils.loadAnimation(this, R.anim.exit_menu);
animation.setFillAfter(true);
animation.setStartOffset(startOffset);
animation.setAnimationListener(new MyAnimationListener());
layout.startAnimation(animation);
} /**
* 进入动画
* @param layout 执行动画的布局文件
*/
public void enterAnimation(RelativeLayout layout) {
animation = AnimationUtils.loadAnimation(this, R.anim.enter_menu);
animation.setFillAfter(true);
animation.setAnimationListener(new MyAnimationListener());
layout.startAnimation(animation);
} /**
* 判断动画是否正在执行
* @author 王松
*
*/
private class MyAnimationListener implements AnimationListener { //动画开始执行
@Override
public void onAnimationStart(Animation animation) {
isAnimationRunning = true;
} //动画执行结束
@Override
public void onAnimationEnd(Animation animation) {
isAnimationRunning = false;
} @Override
public void onAnimationRepeat(Animation animation) {
} }
}

代码中注释已经写的很详细了,这里不再赘述。最后在给大家看看两个动画文件:

enter_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true">
<rotate
android:duration="1000"
android:fromDegrees="-180"
android:toDegrees="0"
android:pivotX="50%"
android:pivotY="100%" />
</set>

exit_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true">
<rotate
android:duration="1000"
android:fromDegrees="0"
android:toDegrees="-180"
android:pivotX="50%"
android:pivotY="100%" />
</set>

关于动画如果不太懂可以看这里android之tween动画详解android之frame动画详解。。

本项目完整代码下载

android自定义控件之模仿优酷菜单的更多相关文章

  1. 自定义View(一)-ViewGroup实现优酷菜单

    自定义View的第一个学习案例 ViewGroup是自动以View中比较常用也比较简单的一种方式,通过组合现有的UI控件,绘制出一个全新的View 效果如下: 主类实现如下: package com. ...

  2. HTML5 CSS3 诱人的实例 :模仿优酷视频截图功能

    一般的视频网站对于用户上传的视频,在用户上传完成后,可以对播放的视频进行截图,然后作为视频的展示图.项目中也可以引入这样的功能给用户一种不错的体验,而不是让用户额外上传一张展示图. 效果图: 看起来还 ...

  3. Android自定义控件:进度条的四种实现方式(Progress Wheel的解析)

    最近一直在学习自定义控件,搜了许多大牛们Blog里分享的小教程,也上GitHub找了一些类似的控件进行学习.发现读起来都不太好懂,就想写这么一篇东西作为学习笔记吧. 一.控件介绍: 进度条在App中非 ...

  4. [转]Android自定义控件:进度条的四种实现方式(Progress Wheel的解析)

    最近一直在学习自定义控件,搜了许多大牛们Blog里分享的小教程,也上GitHub找了一些类似的控件进行学习.发现读起来都不太好懂,就想写这么一篇东西作为学习笔记吧. 一.控件介绍: 进度条在App中非 ...

  5. Android自定义控件4--优酷菜单的菜单键及细节补充

    在上篇文章中实现了优酷菜单执行动画,本文接着完善已经实现的动画功能 本文地址:http://www.cnblogs.com/wuyudong/p/5915958.html ,转载请注明源地址. 已经实 ...

  6. Android自定义控件3--优酷菜单执行动画

    在上篇文章中实现了优酷菜单的布局,本文接着实现动画功能 本文地址:http://www.cnblogs.com/wuyudong/p/5914901.html,转载请注明源地址. 新建动画工具类Ani ...

  7. Android自定义控件2--优酷菜单界面初始化

    本文开始将逐步去实现下面优酷菜单的效果: 本文地址:http://www.cnblogs.com/wuyudong/p/5912538.html,转载请注明源地址. 本文首先来实现优酷菜单界面初始化工 ...

  8. 仿优酷Android客户端图片左右滑动(自动滑动)

    最终效果: 页面布局main.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayou ...

  9. 高仿优酷Android客户端图片左右滑动(自动切换)

    本例是用ViewPager去做的实现,支持自动滑动和手动滑动,不仅优酷网,实际上有很多商城和门户网站都有类似的实现: 具体思路: 1. 工程中需要添加android-support-v4.jar,才能 ...

随机推荐

  1. hdu 3394 Railway

    这是一道用tarjin求双连通分量的题: 其中,不需要修的道路就是桥的数目: 在图的每个极大环中,如果点的数目小于边的数目,显然这个环中含有子环,并且这个环的边数就是这个环中有冲突的边的数目: 如果点 ...

  2. 实战 SSH 端口转发

    转自实战 SSH 端口转发 通过本文的介绍,读者可以从中了解到如何应用 SSH 端口转发机制来解决日常工作 / 生活中的一些问题.学会在非安全环境下使用端口转发来加密网络应用,保护个人隐私以及重要商业 ...

  3. Web 安全之内容安全策略 (CSP)

    内容安全策略 (CSP, Content Security Policy) 是一个附加的安全层,用于帮助检测和缓解某些类型的攻击,包括跨站脚本攻击 (XSS) 和数据注入等攻击. 这些攻击可用于实现从 ...

  4. 算法练习之:Doubles

    Doubles Time Limit: 1000MS Memory Limit: 65536KB Problem Description As part of an arithmetic compet ...

  5. iframe的安全问题

    今天尝试在iframe中嵌入外部网站, 碰到了一些小问题. 如何让自己的网站不被其他网站的iframe引用? 我测试的时候发现我把iframe的src指定到github不起作用. 原来是它把X-Fra ...

  6. 【CF】283D Tennis Game

    枚举t加二分判断当前t是否可行,同时求出s.注意不能说|a[n]| <= |3-a[n]|就证明无解,开始就是wa在这儿了.可以简单想象成每当a[n]赢的时候,两人都打的难解难分(仅多赢一轮): ...

  7. Bear 實驗室: 什麼是Git flow ? 如何在SourceTree使用Git flow管理開發!

      http://www.takobear.tw/12/post/2014/02/bear-git-flow-sourcetreegit-flow.html     Bear 實驗室: 什麼是Git ...

  8. tcp/ip体系-转载

    如果还想在测试这条路上继续走下去的话,那么下面这些东西就是我们必须去掌握的,至少你还不想止步于简单的黑盒测试--其实,一直想去接触Linux下的应用测试,这样能学到东西会很多,而且会非常的受用.之前听 ...

  9. android camera(二):摄像头工作原理、s5PV310 摄像头接口(CAMIF)

    一.摄像头工作原理 上一篇我们讲了摄像头模组的组成,工作原理,做为一种了解.下面我们析摄像头从寄存器角度是怎么工作的.如何阅读摄像头规格书(针对驱动调节时用到关键参数,以GT2005为例). 规格书, ...

  10. oracle删除当前用户下所有表

    1.如果有删除用户的权限,则可以: drop user user_name cascade; 加了cascade就可以把用户连带的数据全部删掉. 删除后再创建该用户.--创建管理员用户create u ...