动画七、动画的PropertyValuesHolder与Keyframe

本学习笔记主要来自启舰:
http://blog.csdn.net/harvic880925/article/details/50752838
在学习过程中融入了自己的理解和思路。
前面掌握了ValueAnimator、ObjectAnimator动画通过通过ofInt(), ofFloat(), ofObject()等方式创建实例,实际上动画实例的创建还有另外的方法:

//valueAnimator的 public ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values){} // ObjectAnimator的 public ObjectAnimator ofPropertyValuesHolder(Object target,PropValueHolder... values){}

也就是说ValueAnimator和ObjectAnimator除了通过ofInt(), ofFloat(), ofObject()创建实例外,还都有一个ofPropertyValuesHolder()方法来创建实例,这篇文章我就带大家来看看如何通过ofPropertyValuesHolder()来创建实例的。
由于ValueAnimator和ObjectAnimator都具有ofPropertyValuesHolder()函数,使用方法也差不多,相比而言,ValueAnimator的使用机会不多,这里我们就只讲ObjectAnimator中ofPropertyValuesHolder()的用法。相信大家懂了这篇以后,再去看ValueAnimator的ofPropertyValuesHolder(),也应该是会用的。
一、PropertyValuesHolder
1、概述
PropertyValuesHolder的意义是:它其中保存了动画过程中所需要操作的属性和对应的值。我们通过ofFloat(Object target, String propertyName, float… values)构造的动画,ofFloat()的内部实现其实就是将传进来的参数封装成PropertyValuesHolder实例来保存动画状态。在封装成PropertyValuesHolder实例以后,后期的各种操作也是以PropertyValuesHolder为主。
PropertyValuesHolder中有很多函数,有些函数的api等级是11,有些函数的api等级是14和21; 高api的函数我们就不讲了,只讲讲api 11的函数的用法。
首先,我们来看看创建实例的函数:
public PropertyValuesHolder ofFloat(String propertyName, float... values){} public PropertyValuesHolder ofInt(String propertyName, int... values){} public PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,Object... values){} public PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values){}

这一段我们着重讲ofFloat、ofInt和ofObject的用法,ofKeyframe我们单独讲。
2、PropertyValuesHolder之ofFloat()、ofInt()
(1)ofFloat()、ofInt():
我们先来看看它们的构造函数:
public static PropertyValuesHolder ofFloat(String propertyName, float... values){} public static PropertyValuesHolder ofInt(String propertyName, int... values){}

propertyName:表示ObjectAnimator需要操作的属性名。即ObjectAnimator需要通过反射查找对应属性的setProperty()函数的那个property.
values:属性所对应的参数,同样是可变长参数,可以指定多个,还记得我们在ObjectAnimator中讲过,如果只指定了一个,那么ObjectAnimator会通过查找getProperty()方法来获得初始值。
(2)、ObjectAnimator.ofPropertyValuesHolder()
public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values){}

target:指需要执行动画的控件;
values:是一个可变长参数,可以传进去多个PropertyValuesHolder实例,由于每个PropertyValuesHolder实例都会针对一个属性做动画,所以如果传进去多个PropertyValuesHolder实例,将会对控件的多个属性同时做动画操作。
下面我们就举个例子来说明如何通过PropertyValuesHolder的ofFloat、ofInt来做动画。
private void doPropertyAnimator() { PropertyValuesHolder holder = PropertyValuesHolder.ofFloat("Rotation", 60f, -60f, 50f, -50f, -40f, 40f, 30f, -30f, 20f, -20f, 10f, -10f, 0f); PropertyValuesHolder holderColor = PropertyValuesHolder.ofInt( "BackgroundColor", 0xfffffff0, 0xffff00ff, 0xffffff00, 0xffffff0f); objectAnimator = ObjectAnimator.ofPropertyValuesHolder( mFlAnimator, holder, holderColor); objectAnimator.setDuration(500); objectAnimator.setRepeatMode(ValueAnimator.REVERSE); objectAnimator.setRepeatCount(ValueAnimator.INFINITE); objectAnimator.setInterpolator(new LinearInterpolator()); objectAnimator.start(); }

其中,mFlAnimator是自定义TextView(ObjTextView)在xml中的布局,ObjTextView如下:
public class ObjTextView extends TextView { public ObjTextView(Context context, AttributeSet attrs) { super(context, attrs); } public void setCharText(Character character){ setText(String.valueOf(character)); } }

Holder对象设定了动画旋转的角度,holderColor对象设定了动画的背景色变化,objectAnimator动画对象里面添加了target控件对象及可变参数Holder和holderColor,当然我们还可以在这里添加别的参数,比如透明度(alpha)的变化,缩放(scale)等动画效果。
3、PropertyValuesHolder之ofObject()
(1)、概述
我们先来看一下ofObject的构造函数:
public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator, Object... values);

参数的含义,再次不多说,不懂的话就找根面条上吊得了。
(2)、示例
public class CharEvaluator implements TypeEvaluator { @Override public Character evaluate(float v, Character character, Character t1) { int start = (int)character; int end = (int)t1; char cha = (char)value; return cha; } }

这段代码简单,前面也已经讲解过很多次了,不多说,不懂的话就找根面条上吊得了。
public class ObjTextView extends TextView { public ObjTextView(Context context, AttributeSet attrs) { super(context, attrs); } public void setCharText(Character character){ setText(String.valueOf(character)); } }

从CharEvaluator中可以看出,从CharEvaluator中产出的动画中间值类型为Character类型。TextView中虽然有setText(CharSequence text) 函数,但这个函数的参数类型是CharSequence,而不是Character类型。所以我们要自定义一个类派生自TextView来改变TextView的字符:
public class ObjTextView extends TextView { public ObjTextView(Context context, AttributeSet attrs) { super(context, attrs); }public void setCharText(Character character){ setText(String.valueOf(character)); } }

这个与之前上面的相同。
动画的代码如下:
private void doPropertyObjAnimator() { PropertyValuesHolder holderText = PropertyValuesHolder.ofObject( "CharText", new CharEvaluator(), new Character('A'), new Character('Z')); PropertyValuesHolder holder = PropertyValuesHolder.ofFloat( "Rotation", 60f, -60f, 50f, -50f, -40f, 40f, 30f, -30f, 20f, -20f, 10f, -10f, 0f); PropertyValuesHolder holderColor = PropertyValuesHolder.ofInt( "BackgroundColor", 0xfffffff0, 0xffff00ff, 0xffffff00, 0xffffff0f); objectAnimator01 = ObjectAnimator.ofPropertyValuesHolder( mFlAnimator, holderText, holder, holderColor); objectAnimator01.setDuration(2000); objectAnimator01.setInterpolator(new LinearInterpolator()); objectAnimator01.setRepeatCount(ValueAnimator.INFINITE); objectAnimator01.setRepeatMode(ValueAnimator.REVERSE); objectAnimator01.start(); }

首先是根据PropertyValuesHolder.ofObject生成一个PropertyValuesHolder实例,注意它的属性就是CharText,所对应的set函数就是setCharText,由于CharEvaluator的中间值是Character类型,所以CharText属性所对应的完整的函数声明为setCharText(Character character);这也就是我们为什么要自定义一个MyTextView原因,就是因为TextView中没有setText(Character character)这样的函数。
二、Keyframe
1、概述:KeyFrame直译过来就是关键帧。 一个关键帧必须包含两个原素,第一时间点,第二位置。即这个关键帧是表示的是某个物体在哪个时间点应该在哪个位置上。
KeyFrame的生成方式为:
Keyframe kf0 = Keyframe.ofFloat(0, 0); Keyframe kf1 = Keyframe.ofFloat(0.1f, -20f); Keyframe kf2 = Keyframe.ofFloat(1f, 0);

上面生成了三个KeyFrame对象,其中KeyFrame的ofInt函数的声明为:
public static Keyframe ofFloat(float fraction, float value);

fraction:表示当前的显示进度,即从加速器中getInterpolation()函数的返回值;
value:表示当前应该在的位置
比如Keyframe.ofFloat(0, 0)表示动画进度为0时,动画所在的数值位置为0;Keyframe.ofFloat(0.25f, -20f)表示动画进度为25%时,动画所在的数值位置为-20;Keyframe.ofFloat(1f,0)表示动画结束时,动画所在的数值位置为0;
在理解了KeyFrame.ofFloat()的参数以后,我们来看看PropertyValuesHolder是如何使用KeyFrame对象的:
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values);

fraction:表示当前的显示进度,即从加速器中getInterpolation()函数的返回值;
value:表示当前应该在的位置
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe( "rotation", frame0, frame1, frame2); mImage, frameHolder); animator.setDuration(1000); animator.start();

2、示例:
private void doOfFloatAnim(){ Keyframe frame0 = Keyframe.ofFloat(0f, 0); Keyframe frame1= Keyframe.ofFloat(0.1f, -20f); Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f); Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f); Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f); Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f); Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f); Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f); Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f); Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f); Keyframe frame10 = Keyframe.ofFloat(1, 0); frameHolder = PropertyValuesHolder.ofKeyframe("rotation", frame0, frame1, frame2, frame3, frame4, frame5, frame6, frame7, frame8, frame9, frame10); frameHolder.setEvaluator(new CharEvaluator()); animator = ObjectAnimator.ofPropertyValuesHolder( mIvKeyframe, frameHolder); animator.setDuration(500); animator.setInterpolator(new LinearInterpolator()); animator.start(); }

3、Keyframe之ofFloat、ofInt与常用函数
(1)、ofFloat、ofInt
其实Keyframe除了ofFloat()以外,还有ofInt()、ofObject()这些创建Keyframe实例的方法,Keyframe.ofObject()我们下部分再讲,这部分,我们着重看看ofFloat与ofInt的构造函数与使用方法:
public static Keyframe ofFloat(float fraction) public static Keyframe ofFloat(float fraction, float value) public static Keyframe ofInt(float fraction) public static Keyframe ofInt(float fraction, int value)

2)、常用函数:
//设置fraction参数,即Keyframe所对应的进度; public void setFraction(float fraction) // 设置当前Keyframe所对应的值; public void setValue(Object value) // 设置Keyframe动作期间插值器; public void setInterpolator(TimeInterpolator interpolator)

这三个函数中,插值器的作用应该是比较难理解,如果给这个Keyframe设置上插值器,那么这个插值器就是从上一个Keyframe开始到当前设置插值器的Keyframe时,这个过程值的计算是利用这个插值器的,比如:
Keyframe frame0 = Keyframe.ofFloat(0f, 0); Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f); frame1.setInterpolator(new BounceInterpolator()); Keyframe frame2 = Keyframe.ofFloat(1f, 20f); frame2.setInterpolator(new LinearInterpolator());

在上面的代码中,我们给frame1设置了插值器BounceInterpolator,那么在frame0到frame1的中间值计算过程中,就是用的就是回弹插值器;
同样,我们给frame2设置了线性插值器(LinearInterpolator),所以在frame1到frame2的中间值计算过程中,使用的就是线性插值器。很显然,给Keyframe.ofFloat(0f, 0)设置插值器是无效的,因为它是第一帧。
4、Keyframe之ofObject
与ofInt,ofFloat一样,ofObject也有两个构造函数:
public static Keyframe ofObject(float fraction); public static Keyframe ofObject(float fraction, Object value);

同样,如果使用ofObject(float fraction)来构造,也必须使用setValue(Object value)来设置这个关键帧所对应的值。我们还以TextView更改字母的例子来使用下Keyframe.ofObject.
private void doKeyframeofObject(){ Keyframe frame0 = Keyframe.ofObject(0f, new Character('A')); Keyframe frame1 = Keyframe.ofObject(0.1f, new Character('L')); Keyframe frame2 = Keyframe.ofObject(1,new Character('Z')); frameHolder02 = PropertyValuesHolder.ofKeyframe( "CharText",frame0,frame1,frame2); frameHolder02.setEvaluator(new CharEvaluator()); animator02 = ObjectAnimator.ofPropertyValuesHolder( mFlAnimator, frameHolder); animator02.setDuration(3000); animator02.start(); }

利用关键帧创建PropertyValuesHolder后,一定要记得设置自定义的Evaluator:
frameHolder02.setEvaluator(new CharEvaluator());

凡是使用ofObject来做动画的时候,都必须调用frameHolder.setEvaluator显示设置Evaluator,因为系统根本是无法知道,你动画的中间值Object真正是什么类型的。
如果去掉第0帧,将以第一个关键帧为起始位置
如果去掉结束帧,将以最后一个关键帧为结束位置
使用Keyframe来构建动画,至少要有两个或两个以上帧
三、PropertyValuesHolder的其它函数
// 设置动画的Evaluator public void setEvaluator(TypeEvaluator evaluator); // 用于设置ofFloat所对应的动画值列表 public void setFloatValues(float... values); // 用于设置ofInt所对应的动画值列表 public void setIntValues(int... values); // 用于设置ofKeyframe所对应的动画值列表 public void setKeyframes(Keyframe... values); // 用于设置ofObject所对应的动画值列表 public void setObjectValues(Object... values); // 设置动画属性名 public void setPropertyName(String propertyName);

【动画七、动画的PropertyValuesHolder与Keyframe】这些函数都比较好理解。
如果是利用PropertyValuesHolder.ofObject()来创建动画实例的话,我们是一定要显示调用 PropertyValuesHolder.setEvaluator()来设置Evaluator的。谨记!谨记!!谨记!!!

    推荐阅读