功能强大的动画系统——属性动画(一)

1.前言


通过上一讲的内容,可以知道补间动画能实现我们大部分的界面效果。但是,作为最早引入的动画系统,仍有一些令人不满意的地方。

  • 动画种类有限,只能是透明度、位移、旋转、缩放这几种动画效果及其组合。所能做的,就是通过Interpolator改变动画进行中的效果。
  • 动画效果仅仅是视图层面的,对控件的实际并没有影响。

而导致这些的原因,就是因为动画的操作对象是控件的行为,所以无法对控件本身做出改变。

2.属性动画


安卓后来推出属性动画的目的就是为了弥补补间动画的缺陷。因为它可以对控件的属性进行操作,默认支持float,int和六位十六进制颜色。若属性不在这个范围内,自己提供一个TypeEvaluator转换即可。而且,可以与补间动画共用系统提供的Interpolator,并通过Keyframe和AnimatorSet扩展对动画的控制。


功能强大的动画系统——属性动画(一)_第1张图片
property animation.png

3.具体使用


拿最具代表性的ObjectAnimator来说吧,只需调用实例的start()方法就可以启动动画,所以构建ObjectAnimator实例就是原生动画最核心的部分。系统提供了三种创建实例的方法:

  • 通过ObjectAnimator.ofXXX()的方法生成动画对象。
  • 新建ObjectAnimator对象,再通过setXXX()的方法添加所需参数。
  • 通过AnimatorInflater.loadAnimator(Context context, int id) 的方法加载XML的配置文件,生成动画对象。文件放在res/animator文件夹下,通过R.animator.XXX来引用。

我们先看看,ObjectAnimator的XML属性有哪些,以及代码中如何设置:

android:propertyName
必需,进行动画的属性的名称,对应控件中setXXX方法(驼峰命名)。映射时,默认只将属性名第一个字母大写,所以其它必须符合驼峰命名。
由于执行动画的控件不能在XML中设置,必须在代码中调用setTarget(Object target) 绑定。
代码表示:setPropertyName(String propertyName) 

android:valueTo
必需,动画结束时属性的值。
代码表示:setFloatValues(float... values) / setIntValues(int... values)

android:valueFrom
动画开始时属性的值。若没有指定,将从控件属性对应的get方法中获得。若还没有,则使用数据类型的默认值。
代码表示:setFloatValues(float... values) / setIntValues(int... values)

android:duration
动画执行的时间,毫秒为单位,默认300毫秒。
代码表示:setDuration(long duration) 

android:startOffset
start()方法调用后,动画延迟播放的时间,毫秒为单位。
代码表示:setStartDelay(long startDelay) ,父类的方法。

android:repeatCount 
定义动画被重复执行的次数。默认值是0,而-1(INFINITE)表示无限循环。
代码表示:setRepeatCount(int value) ,父类的方法。

android:repeatMode
当repeatCount>0或者=-1,且动画执行到了终值时,进行的重复行为的类型。
repeat(RESTART)是默认值,表示从头开始。reverse(REVERSE),表示反向开始。
代码表示:setRepeatMode(int value) ,父类的方法。

android:interpolator
插值器,与补间动画中的作用相同,可以共用。默认是AccelerateDecelerateInterpolator。
代码表示:setInterpolator(TimeInterpolator value) ,父类的方法。

android:valueType
关键字,若类型是颜色,不设置此属性。
floatType是默认值,表示为浮点型。intType,表示为整型。
代码表示:无相应的方法。

由这些属性我们可以发现propertyName决定了属性动画比补间动画要强大,夸张点说,View及其子类有多少set开头的方法,就有多少种动画。那么实现补间动画的效果对于属性动画而言不难:

// 透明度:alpha
void setAlpha(float alpha)

// 位移:translationX、translationY
void setTranslationX(float translationX) 
void setTranslationY(float translationY)

// 中心点:pivotX、pivotY
void setPivotX(float pivotX) 
void setPivotY(float pivotY) 

// 旋转:rotation、rotationX、rotationY
void setRotation(float rotation)
void setRotationX(float rotationX)
void setRotationY(float rotationY)

// 缩放:scaleX、scaleY
void setScaleX(float scaleX)
void setScaleY(float scaleY)

根据上面的属性可以很容易地用后两种方式写出动画,但是系统给我们提供了更简单的,也就是第一种方式。

// 第一个参数指定执行动画的控件对象。
// 第二个参数指定被动画操作的控件的属性名,与android:propertyName用法一致。
// 第三个是可变参数,指定动画值的改变轨迹。由于参数数量不定,变化更加灵活。
ObjectAnimator.ofFloat(Object target, String propertyName, float... values) 
ObjectAnimator.ofInt(Object target, String propertyName, int... values) 
// API 21为了支持alpha值引入的
ObjectAnimator.ofArgb(Object target, String propertyName, int... values) 

属性动画推荐用代码进行实现,因为使用XML配置就和补间动画一样只有开始值和结束值,变化过于单一,若通过Interpolator进行调整,需要自己设计轨迹表达式,比较麻烦,大部分人不会和自己过不去。
  与补间动画相比,仍有个问题没有解决,一个动画只能对一个属性进行改变,多个动画如何组合起来。肯定就是AnimatorSet,它特有的属性只有一个(与补间动画一样,对它设置的公共属性,有的是覆盖子动画的同名属性,有的对它自己起作用,有的直接忽略,不推荐使用):

android:ordering 
关键字,指定此集合中动画的播放顺序。
together是默认值,表示同一时间内播放动画。sequentially,表示按顺序进行播放动画,注意避免出现循环。
代码表示:
playTogether(Collection items) 
playTogether(Animator... items) 
playSequentially(List items) 
playSequentially(Animator... items) 

这种将动画一次性加入,设定播放顺序,让子动画根据自己的设置播放,显得不够精细,无法处理同时播放和顺序播放混合的动画。所以,添加了play(Animator anim) 方法,使用构造器模式,一个一个地添加动画,并设置播放关系。详细的方法如下图所示:


功能强大的动画系统——属性动画(一)_第2张图片
AnimatorSet.Builder.png

动画多了后,对于延迟的处理比较麻烦。延迟有个概念要理解,它指的是在动画的播放前加了等待时间,也就是说,被延迟的动画是非播放状态的。所以AnimatorSet的延迟对所有子动画起作用,毕竟动画都没被启动,而两个动画一起播放,是指一个动画启动另一个动画,启动的必然处于播放状态,被启动的可能处于延迟状态,切记。

4.内容解释


由于属性动画的功能比补间动画多了太多,既有相似的,又有完全新的概念,实在不知道按什么顺序写。这一讲是从补间动画过渡到属性动画,所以内容上尽量保持一致,毕竟比它强大的前提是能实现它。大家可以对比理解。

你可能感兴趣的:(功能强大的动画系统——属性动画(一))