动画七、动画的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.ofObject()来创建动画实例的话,我们是一定要显示调用 PropertyValuesHolder.setEvaluator()来设置Evaluator的。谨记!谨记!!谨记!!!

你可能感兴趣的:(Android动画系列)