自定义控件——旋转动画实例

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、优酷菜单动画效果图展示

  • 还没旋转的状态

在这里插入图片描述

  • 旋转分析:
    本文以逆时针方向旋转展示效果
    思维扩展:
    1.先确定好动画旋转分析
    2.旋转中心点(此处把x轴和y轴看成单位长度 1,故中心点为(0.5,1)
    在这里插入图片描述

二、代码部分

  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>
  1. 工具类
    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) {

        }
    }
}
  1. 主函数代码
    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);
}

在这里插入图片描述

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值