提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、优酷菜单动画效果图展示
- 还没旋转的状态
- 旋转分析:
本文以逆时针方向旋转展示效果:
思维扩展:
1.先确定好动画旋转分析
2.旋转中心点(此处把x轴和y轴看成单位长度 1,故中心点为(0.5,1)
二、代码部分
- 布局文件:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:id="@+id/rl_level1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_alignParentBottom="true"
android:background="@drawable/level1">
<ImageButton
android:id="@+id/ib_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_home"
android:background="@null"
android:layout_centerInParent="true"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_level2"
android:layout_width="240dp"
android:layout_height="108dp"
android:layout_centerInParent="true"
android:layout_alignParentBottom="true"
android:background="@drawable/level2">
<ImageButton
android:id="@+id/ib_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_menu"
android:background="@null"
android:layout_centerHorizontal="true"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_myyouku"
android:background="@null"
android:layout_marginLeft="5dp"
android:layout_marginTop="65dp"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_search"
android:background="@null"
android:layout_marginLeft="190dp"
android:layout_marginTop="65dp"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_level3"
android:layout_width="360dp"
android:layout_height="170dp"
android:layout_centerInParent="true"
android:layout_alignParentBottom="true"
android:background="@drawable/level3">
<ImageButton
android:layout_marginTop="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/channel4"
android:background="@null"
android:layout_centerHorizontal="true"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/channel1"
android:background="@null"
android:layout_marginLeft="10dp"
android:layout_marginTop="125dp"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/channel2"
android:background="@null"
android:layout_marginLeft="40dp"
android:layout_marginTop="70dp"/>
<ImageButton
android:layout_marginLeft="85dp"
android:layout_marginTop="25dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/channel3"
android:background="@null" />
<ImageButton
android:layout_marginLeft="235dp"
android:layout_marginTop="25dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/channel5"
android:background="@null" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/channel6"
android:background="@null"
android:layout_marginLeft="280dp"
android:layout_marginTop="70dp"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/channel7"
android:background="@null"
android:layout_marginLeft="305dp"
android:layout_marginTop="125dp"/>
</RelativeLayout>
</RelativeLayout>
- 工具类
AnimationUtils
/**
2. 旋转动画工具类
*/
public class AnimationUtils {
//正在执行动画的个数
public static int runningAnimationCount=0;
/**
* 旋转出去的动画
* @param layout 表示要控制的参数类型在相对布局里面
* @param delay 表示延迟的时间参数
*/
public static void rotateOutAnim(RelativeLayout layout,long delay){
//当动画旋转出去的时候,不可以执行点击效果
int childCount = layout.getChildCount();
//找到所有的子view,并禁用其点击功能
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);
}
/**
* 旋转进来的动画
* @param layout 表示要控制的参数类型在相对布局里面
* @param delay 表示延迟的时间参数
*/
public static void rotateInAnim(RelativeLayout layout,long delay){
//当动画旋转出去的时候,不可以执行点击效果
int childCount = layout.getChildCount();
//找到所有的子view,并禁用其点击功能
for (int i = 0; i < childCount; i++) {
layout.getChildAt(i).setEnabled(true);
}
RotateAnimation ra=new RotateAnimation(
-180f,0f,//表示开始和结束的角度 顺时针方向
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);
}
/**
* 给动画设置监听事件
*/
static class MyAnimationListener implements Animation.AnimationListener{
@Override
public void onAnimationStart(Animation animation) {
runningAnimationCount++;
}
@Override
public void onAnimationEnd(Animation animation) {
runningAnimationCount--;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
}
}
- 主函数代码
MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private static final String TAG=MainActivity.class.getSimpleName();
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);
// 初始化控件
initViews();
}
private void initViews() {
// 添加点击事件
findViewById(R.id.ib_home).setOnClickListener(this);
findViewById(R.id.ib_menu).setOnClickListener(this);
rl_level1 = (RelativeLayout) findViewById(R.id.rl_level1);
rl_level2 = (RelativeLayout) findViewById(R.id.rl_level2);
rl_level3 = (RelativeLayout) findViewById(R.id.rl_level3);
}
@Override
public void onClick(View v) {
//如果当前有动画还在执行,则后续点击状态不执行
if (AnimationUtils.runningAnimationCount>0){
return;
}
if (v.getId()==R.id.ib_home){
if (isLevel2Display){
long delay=0;//用于延迟执行动画的时间
//如果第三级菜单是显示的,则先转出去
if (isLevel3Display){
AnimationUtils.rotateOutAnim(rl_level3,0);
isLevel3Display=false;
delay+=200;
}
AnimationUtils.rotateOutAnim(rl_level2,delay);
}else {
//如果二级菜单不是显示状态,则转出来
AnimationUtils.rotateInAnim(rl_level2,0);
}
isLevel2Display=!isLevel2Display;//把执行过后的状态置反
} else if (v.getId() == R.id.ib_menu) {
//如果第三级菜单是显示的,则转出去
if (isLevel3Display){
AnimationUtils.rotateOutAnim(rl_level3,0);
}else {
//如果三级菜单不是显示状态,则转出来
AnimationUtils.rotateInAnim(rl_level3,0);
}
isLevel3Display=!isLevel3Display;//把执行过后的状态置反
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//keyCode 事件码
Log.i(TAG, "onKeyDown: "+keyCode);
if (keyCode==KeyEvent.KEYCODE_MENU){
if (AnimationUtils.runningAnimationCount>0){
//当前有动画正在执行,取消当前事件
return true;
}
//如果按下的是菜单按钮
if (isLevel1Display){
long delay=0;
//隐藏三级菜单
if (isLevel3Display){
AnimationUtils.rotateOutAnim(rl_level3,0);
isLevel3Display=false;
delay+=200;
}
//隐藏二级菜单
if (isLevel2Display){
AnimationUtils.rotateOutAnim(rl_level2,delay);
isLevel2Display=false;
delay+=200;
}
//隐藏一级菜单
AnimationUtils.rotateOutAnim(rl_level1,delay);
}else {
//顺次转进来
AnimationUtils.rotateInAnim(rl_level1,0);
AnimationUtils.rotateInAnim(rl_level2,200);
AnimationUtils.rotateInAnim(rl_level3,400);
isLevel3Display=true;
isLevel2Display=true;
}
isLevel1Display=!isLevel1Display;
return true;//消费了当前事件
}
return super.onKeyDown(keyCode, event);
}
}
总结
收获:
思维方式上:
1.使用补间动画的时候,在隐藏动画的同时,需要借助遍历其布局下的控件属性,把控件设置成点击无反应状态
//当动画旋转出去的时候,不可以执行点击效果
int childCount = layout.getChildCount();
//找到所有的子view,并禁用其点击功能
for (int i = 0; i < childCount; i++) {
layout.getChildAt(i).setEnabled(true);
}
2.需要什么条件的时候,就传对应的参数
例如上面的图片所示:
第一个参数是为了控件该布局里面的控件
第二个参数是为了设置延迟时间
3.需要把动画设置成先后顺序(先执行完一个,在执行下一个)
可以设置点击监听,如果还有正在执行的,则点击没有效果
4.获取手机硬件按钮的方法
onKeyDown()
:监听手机屏幕上的按键
比如我们经常退出某款程序时,按back键后,会提示,再按一次退出!
private long clickTime =0L;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//前后按键不能超过2秒,否则进行友好提示
if (System.currentTimeMillis() - clickTime > 2000) {
Toast.makeText(this, "再按一次退出!", Toast.LENGTH_SHORT).show();
clickTime = System.currentTimeMillis();
} else {
finish();
}
return true;
}
return super.onKeyDown(keyCode, event);
}