android属性动画实践及原理

动画

首先明确啥是动画?你可以理解成若干不同图片随着时间不断交替成为焦点的过程,说简单点就是"量子阅读法",你还可以把动画理解成使用某多种手段将一张图片进行各种变换。那么这两种理解方式对应android里的动画就是帧动画和属性动画,当然帧动画和补间动画属于视图动画,所以android动画可以分为两大类:视图动画和属性动画

View动画操作对象是view,而属性对象操作的是任何对象甚至是无对象。
View动画基本上只支持4中动画效果,也就是最简单的平移、旋转、缩放、透明度。当然如果你不满足这4中基本动画效果,你也可以自定义view效果,基本思路就是继承Animation抽象性类,重写两个方法:initialize和applyTransformation方法,在applyTransformation中进行相关矩阵变换,为了简化matrix变化,使用camera简化变换过程。总体来说自定义View动画不是很难,而且套路比较固定。
当然view动画也不是一无是处,他在viewGroup中控制子view的出场退场效果,他在Activity中实现Activity之间的切换动画。

引用一个大佬对view动画的总结:

View动画还有一个致命的缺陷,就是它只是改变了View的显示效果而已,而不会真正去改变View的属性。什么意思呢?比如说,现在屏幕的左上角有一个按钮,然后我们通过补间动画将它移动到了屏幕的右下角,现在你可以去尝试点击一下这个按钮,点击事件是绝对不会触发的,因为实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。

下面我们重点介绍属性动画,它在实际中使用比较多。

属性动画

字面上的意思就是动态改变对象的属性值来实现动画效果,比如,让某个对象的宽度在10秒内增大50dp。别看这句话很短,但是实现起来需要考虑一下几个问题:

  1. 判断对象是否有这个”宽度“这个属性?若有怎么获取?若没有又怎么解决?
  2. 如何控制对象的宽度从原始宽度在10秒之内遍到指定宽度?匀速?变速?
  3. 如何检测感知对象的宽度变化了?

下面我们带着这几个思考继续开始学习吧
常用的几种属性动画有:ValueAnimator、ObjectAnimator、AnimatorSet类。其中ObjectAnimator继承了ValueAnimator。ValueAnimator是属性动画的核心类

ValueAnimator

属性动画的运行机制是通过不断地对属性值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。
ValueAnimator使用起来十分简单:
比如我想将一个值从0变到1,时长5000ms,就可以这样写:

ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
anim.setDuration(5000);
anim.start();

这里我们可以回答开头提出来的第2点思考,如何控制这个速度,如果我不想他变化很快或者太慢。android提供了一个叫做插值器的东东Interpolator,他用来控制改变属性值得变化速率。常见的有AccelerateDecelerateInterpolator(开始和结束变化慢、中间变化快)、LinearInterpolator(匀速变化)、BounceInterpolator(结束的时候出现反弹变化效果) 。说白了,插值器通过数学函数将一段时间段进行(非)线性流逝,从而实现渐变的动画效果。

anim.setInterpolator(new BounceInterpolator());//反弹插值器

接下来我们可以回答开头提出来的第3点思考,如何感知对象属性变化了?只有感知变化了我才好决定去做变化依赖的操作,比如我要实现一个button的宽度从0变化到100dp,ValueAnimator类不断set这个button的宽度属性,而没有进行其他改变button宽度的行为,所以逻辑时先得监听到属性值发生变化了然后去在ui层面上改变button的宽度。
好在android可以在添加监听器AnimatorUpdateListener实现对属性值的监听:

anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
   
      	//获取当前width变化到的值
        curWidth= (int) anim.getAnimatedValue();
        //更新ui
        invalidate();
      }
    });

所以ValueAnimator只需要我们提供起始值、终点值已经自己选取一个插值器(也可以自己定义,android已经做到完全不需要我们自己定义了),最后提供一个自定义的监听器实现属性值改变后的后操作。

ObjectAnimator

相比ValueAnimator,ObjectAnimator可能是我们开发中最常使用到的,因为ValueAnimator提供的ObjectAnimator都能实现,ObjectAnimator可以对任何对象直接做任何操作,这就是他强大之处。
比如我要对一个对象向右平移一个对象宽度:

ObjectAnimator.ofFloat(targetObj,"translationX",targetObj.getWidth()).setDuration(5000).setInterpolator(new BounceInterpolator()).start();

是不是感觉代码十分清爽,ObjectAnimator也不需要像ObjectAnimator需要设置还设置什么属性监听器,他做到了对对象属性值改变、动画时长、插值器设置链式构造。
当然ObjectAnimator也提供了用于监听动画播放过程的监听器AnimatorListener/AnimatorAdaptor,用于对动画开始、结束、取消等一些状态的回调。
下面我们可以回答第2点思考,ObjectAnimator是如何对对象进行属性赋值的?答案是通过调用该对象的getter和setter方法,getter方法可以不用提供,但是如何用户没有提供对象的初始值,那么系统就会使用getter方法找对象的初始值,若没getter方法就会报错。

所以这就可以解释得通为啥button并没有width这个属性值,但还是可以使用动画作用于width上,那是因为他有getWidth和setWidth方法。
我们借用《Android开发艺术探索》中的例子,改变button的宽度:点击button,改变button宽度:

@Override
  public void onClick(View v) {
   
    switch (v.getId()){
   
      case R.id.bt_button:
        changeButton();
        break;
    }
  }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值