1.前言
通过上一讲的内容,可以知道补间动画能实现我们大部分的界面效果。但是,作为最早引入的动画系统,仍有一些令人不满意的地方。
- 动画种类有限,只能是透明度、位移、旋转、缩放这几种动画效果及其组合。所能做的,就是通过Interpolator改变动画进行中的效果。
- 动画效果仅仅是视图层面的,对控件的实际并没有影响。
而导致这些的原因,就是因为动画的操作对象是控件的行为,所以无法对控件本身做出改变。
2.属性动画
安卓后来推出属性动画的目的就是为了弥补补间动画的缺陷。因为它可以对控件的属性进行操作,默认支持float,int和六位十六进制颜色。若属性不在这个范围内,自己提供一个TypeEvaluator转换即可。而且,可以与补间动画共用系统提供的Interpolator,并通过Keyframe和AnimatorSet扩展对动画的控制。
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<Animator> items)
playTogether(Animator... items)
playSequentially(List<Animator> items)
playSequentially(Animator... items)
这种将动画一次性加入,设定播放顺序,让子动画根据自己的设置播放,显得不够精细,无法处理同时播放和顺序播放混合的动画。所以,添加了play(Animator anim) 方法,使用构造器模式,一个一个地添加动画,并设置播放关系。详细的方法如下图所示:
动画多了后,对于延迟的处理比较麻烦。延迟有个概念要理解,它指的是在动画的播放前加了等待时间,也就是说,被延迟的动画是非播放状态的。所以AnimatorSet的延迟对所有子动画起作用,毕竟动画都没被启动,而两个动画一起播放,是指一个动画启动另一个动画,启动的必然处于播放状态,被启动的可能处于延迟状态,切记。
4.内容解释
由于属性动画的功能比补间动画多了太多,既有相似的,又有完全新的概念,实在不知道按什么顺序写。这一讲是从补间动画过渡到属性动画,所以内容上尽量保持一致,毕竟比它强大的前提是能实现它。大家可以对比理解。