Android 动画(六)PropertyValuesHolder学习

本文详细介绍了PropertyValuesHolder在Android动画中的使用,包括ofFloat(), ofInt(), ofObject()方法,以及Keyframe的关键帧概念和应用。通过示例代码展示了如何创建和设置动画,帮助开发者更好地理解和实现复杂动画效果。" 131369257,11824147,Python并发编程:线程结束等待策略,"['Python', '并发编程', '开发语言']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PropertyValuesHolder

ObjectAnimator只能对单个属性进行操作,如果想实现比较复杂的效果就需要用到PropertyValuesHolder了。

1.1、概述

PropertyValuesHolder这个类的意义就是,它其中保存了动画过程中所需要操作的属性和对应的值。我们通过ofFloat(Object target, String propertyName, float… values)构造的动画,ofFloat()的内部实现其实就是将传进来的参数封装成 PropertyValuesHolder实例来保存动画状态。在封装成 PropertyValuesHolder实例以后,后期的各种操作也是以 PropertyValuesHolder 为主的。

创建PropertyValuesHolder实例的函数:

public static PropertyValuesHolder ofFloat(String propertyName, float... values)  
public static PropertyValuesHolder ofInt(String propertyName, int... values)   
public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,Object... values)  
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values)  
1.2、PropertyValuesHolder 之 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 的 ofFloat 如下:

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values);

可以看到在 ObjectAnimator.ofFloat 中只比 PropertyValuesHolder 的 ofFloat 多了一个target,其它都是完全一样的!

将构造的PropertyValuesHolder实例设置进 ObjectAnimator:

public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)

其中:

参数描述
target:指需要执行动画的控件
values:是一个可变长参数,可以传进去多个 PropertyValuesHolder 实例,由于每个 PropertyValuesHolder 实例都会针对一个属性做动画,所以如果传进去多个 PropertyValuesHolder 实例,将会对控件的多个属性同时做动画操作。

示例代码:
xml:

            <Button
                android:id="@+id/bt_start_anim01"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="启动动画(PropertyValuesHolder)"/>

            <ImageView
                android:id="@+id/iv_image01"
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:layout_gravity="center"
                android:src="@drawable/gold_coin"/>

java代码:

    /**
     * 使用PropertyValuesHolder 设置复杂动画
     */
    private void startAnim01() {
        PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("Rotation", 50f, -50f, 30f, -30f, 20f, -20f, 10f, -10f, 0f);
        PropertyValuesHolder scaleXHolder = PropertyValuesHolder.ofFloat("ScaleX", 1f, 2f);
        PropertyValuesHolder scaleYHolder = PropertyValuesHolder.ofFloat("ScaleY", 1f, 2f);
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(ivImage01, rotationHolder, scaleXHolder, scaleYHolder);
        animator.setDuration(2000);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();
    }

实现效果:
这里写图片描述

1.3. PropertyValuesHolder 之 ofObject()

ofObject 的构造函数如下:

public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,Object... values)  
参数描述
propertyName:ObjectAnimator动画操作的属性名;evaluator:Evaluator 实例,Evaluator 是将当前动画进度计算出当前值的类,可以使用系统自带的 IntEvaluator、FloatEvaluator 也可以自定义。
values:可变长参数,表示操作动画属性的值 它的各个参数与 ObjectAnimator.ofObject的类似,只是少了 target 参数而已

示例代码:
xml:

            <Button
                android:id="@+id/bt_start_anim02"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="启动Object动画(PropertyValuesHolder)"/>

            <com.makesky.studydemo01.Animator.MyTextView
                android:id="@+id/tv_text01"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="*"/>

java:

    /**
     * 定义一个对象,用于存值以及传值
     */
    class MyAnimObject {
        public int value;

        public MyAnimObject(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

    /**
     * 自定义对象动画算值器
     * 返回的结果是传入值的两倍
     */
   private class MyAnimObjectEvaluator implements TypeEvaluator<MyAnimObject> {

        @Override
        public MyAnimObject evaluate(float fraction, MyAnimObject startValue, MyAnimObject endValue) {
            int oldValue = startValue.value;
            int newValue = endValue.value;

            int res = (int) ((oldValue + newValue) * fraction) * 2;
            return new MyAnimObject(res);
        }
    }


    /**
     * 通过PropertyValuesHolder传递自定义对象到自定义View中 实现自定义View Object动画
     */
    private void startAnim02() {
        LogUtil.i(TAG, "启动动画");
        MyTextView tvText01=this.findViewById(R.id.tv_text01);
        PropertyValuesHolder myTextHolder = PropertyValuesHolder.ofObject("TextValue", new MyAnimObjectEvaluator(), new MyAnimObject(0), new MyAnimObject(20));
        ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(tvText01, myTextHolder);
        objectAnimator.setDuration(3000);
        objectAnimator.setInterpolator(new LinearInterpolator());
        objectAnimator.start();
    }

MyTextView.java

public class MyTextView extends TextView {


    public MyTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public void setTextValue(ObjectAnimatorDemo02Activity.MyAnimObject object) {
        setText(""+object.getValue());
    }
}

这里写图片描述

1.4、PropertyValuesHolder 之 Keyframe

KeyFrame 主要用于自定义控制动画速率,KeyFrame 直译过来就是关键帧。 而关键帧这个概念是从动画里学来的,一个关键帧必须包含两个原素,第一时间点,第二位置。所以这个关键帧是表示的是某个物体在哪个时间点应该在哪个位置上。比如我们要让一个球在 30 秒时间内,从(0,0)点运动到(300,200)点,那 flash 是怎么来做的呢,在 flash 中,我们只需要定义两个关键帧,在动画开始时定义一个,把球的位置放在(0,0)点;在 30 秒后,再定义一个关键帧,把球的位置放在(300,200)点。在动画 开始时,球初始在是(0,0)点,30 秒时间内就 adobe flash 就会自动填充,把球平滑移动到第二个关键帧的位置(300,200)点;

KeyFrame 使用流程如下:

Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
Keyframe frame2 = Keyframe.ofFloat(1, 0);  
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2);  
 Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage,frameHolder);  
animator.setDuration(1000);  
animator.start(); 
  1. 生成 Keyframe 对象;
  2. 利用 PropertyValuesHolder.ofKeyframe()生成 PropertyValuesHolder 对象
  3. ObjectAnimator.ofPropertyValuesHolder()生成对应的 Animator

注意:在设置ObjectAnimator.ofPropertyValuesHolder()时
1. 如果去掉第 0 帧【Keyframe.ofFloat(0f, 0); 】,将以传入的第一个关键帧为起始位置
2. 如果去掉结束帧【Keyframe.ofFloat(1f,0);】,将以传入最后一个关键帧为结束位置
3. 使用 Keyframe 来构建动画,至少要有两个或两个以上帧。

KeyFrame的一些常用方法:

方法描述
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;
public void setFraction(float fraction)设置 fraction 参数,即 Keyframe 所对应的进度
public void setValue(Object value)设置当前 Keyframe 所对应的值
public void setInterpolator(TimeInterpolator interpolator)设置 Keyframe 动作期间所对应的插值器,设置的这个插值器是从上一个 Keyframe 开始到当前设置插值器的 Keyframe 时,这个过程值的计算是利用这个插值器的,如果这里没有设置插值器,会使用默认的线性插值器(LinearInterpolator)

示例代码:

    /**
     * 通过PropertyValuesHolder设置Keyframe 实现自定义控制动画速率以及多种动画效果
     */
    private void startAnim03() {

        /**
         * 左右转动
         */
        Keyframe rotationKeyframe01= Keyframe.ofFloat(0,0);
        Keyframe rotationKeyframe02= Keyframe.ofFloat(0.1f,-20f);
        rotationKeyframe02.setInterpolator(new AccelerateInterpolator());
        Keyframe rotationKeyframe03= Keyframe.ofFloat(0.2f,20f);
        Keyframe rotationKeyframe04= Keyframe.ofFloat(0.3f,-20f);
        Keyframe rotationKeyframe05= Keyframe.ofFloat(0.4f,20f);
        Keyframe rotationKeyframe06= Keyframe.ofFloat(0.5f,-20f);
        Keyframe rotationKeyframe07= Keyframe.ofFloat(0.6f,20f);
        Keyframe rotationKeyframe08= Keyframe.ofFloat(0.7f,-20f);
        Keyframe rotationKeyframe09= Keyframe.ofFloat(0.8f,20f);
        Keyframe rotationKeyframe10= Keyframe.ofFloat(0.9f,-20f);
        Keyframe rotationKeyframe11= Keyframe.ofFloat(1f,0);

        PropertyValuesHolder frameHolder01 = PropertyValuesHolder.ofKeyframe("rotation",
                rotationKeyframe01,
                rotationKeyframe02,
                rotationKeyframe03,
                rotationKeyframe04,
                rotationKeyframe05,
                rotationKeyframe06,
                rotationKeyframe07,
                rotationKeyframe08,
                rotationKeyframe09,
                rotationKeyframe10,
                rotationKeyframe11
        );

        /**
         * scaleX X轴放大1.5倍
         */
        Keyframe scaleXKeyframe01= Keyframe.ofFloat(0,1);
        Keyframe scaleXKeyframe02= Keyframe.ofFloat(0.1f,1.5f);
        Keyframe scaleXKeyframe03= Keyframe.ofFloat(0.2f,1.5f);
        Keyframe scaleXKeyframe04= Keyframe.ofFloat(0.3f,1.5f);
        Keyframe scaleXKeyframe05= Keyframe.ofFloat(0.4f,1.5f);
        Keyframe scaleXKeyframe06= Keyframe.ofFloat(0.5f,1.5f);
        Keyframe scaleXKeyframe07= Keyframe.ofFloat(0.6f,1.5f);
        Keyframe scaleXKeyframe08= Keyframe.ofFloat(0.7f,1.5f);
        Keyframe scaleXKeyframe09= Keyframe.ofFloat(0.8f,1.5f);
        Keyframe scaleXKeyframe10= Keyframe.ofFloat(0.9f,1.5f);
        Keyframe scaleXKeyframe11= Keyframe.ofFloat(1f,1);
        PropertyValuesHolder frameHolder02 = PropertyValuesHolder.ofKeyframe(
                "ScaleX",
                scaleXKeyframe01,
                scaleXKeyframe02,
                scaleXKeyframe03,
                scaleXKeyframe04,
                scaleXKeyframe05,
                scaleXKeyframe06,
                scaleXKeyframe07,
                scaleXKeyframe08,
                scaleXKeyframe09,
                scaleXKeyframe10,
                scaleXKeyframe11
        );

        /**
         * scaleY Y轴放大1.5倍
         */
        Keyframe scaleYKeyframe01= Keyframe.ofFloat(0,1);
        Keyframe scaleYKeyframe02= Keyframe.ofFloat(0.1f,1.5f);
        Keyframe scaleYKeyframe03= Keyframe.ofFloat(0.2f,1.5f);
        Keyframe scaleYKeyframe04= Keyframe.ofFloat(0.3f,1.5f);
        Keyframe scaleYKeyframe05= Keyframe.ofFloat(0.4f,1.5f);
        Keyframe scaleYKeyframe06= Keyframe.ofFloat(0.5f,1.5f);
        Keyframe scaleYKeyframe07= Keyframe.ofFloat(0.6f,1.5f);
        Keyframe scaleYKeyframe08= Keyframe.ofFloat(0.7f,1.5f);
        Keyframe scaleYKeyframe09= Keyframe.ofFloat(0.8f,1.5f);
        Keyframe scaleYKeyframe10= Keyframe.ofFloat(0.9f,1.5f);
        Keyframe scaleYKeyframe11= Keyframe.ofFloat(1f,1);
        PropertyValuesHolder frameHolder03 = PropertyValuesHolder.ofKeyframe(
                "ScaleY",
                scaleYKeyframe01,
                scaleYKeyframe02,
                scaleYKeyframe03,
                scaleYKeyframe04,
                scaleYKeyframe05,
                scaleYKeyframe06,
                scaleYKeyframe07,
                scaleYKeyframe08,
                scaleYKeyframe09,
                scaleYKeyframe10,
                scaleYKeyframe11
        );

        ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(ivImage03, frameHolder01,frameHolder02,frameHolder03);
        objectAnimator.setDuration(1000);
        objectAnimator.start();
    }

实现的效果:
这里写图片描述

1.5 PropertyValuesHolder 一些常用方法

PropertyValuesHolder 除了上面的讲到的 ofInt,ofFloat,ofObject,ofKeyframe 以外,api 11 的还有几个函数:

方法描述
public void setEvaluator(TypeEvaluator evaluator)设置动画的Evaluator
public void setFloatValues(float… values)用于设置 ofFloat 所对应的动画值列表
public void setIntValues(int… values)用于设置 ofInt 所对应的动画值列表
public void setKeyframes(Keyframe… values)用于设置 ofKeyframe 所对应的动画值列表
public void setObjectValues(Object… values)用于设置 ofObject 所对应的动画值列表 注意:使用 PropertyValuesHolder.ofObject()来创建动画实例的话,一定要显示调用 PropertyValuesHolder.setEvaluator()来设置 Evaluator 的。
public void setPropertyName(String propertyName)用于设置 PropertyValuesHolder 所需要操作的动画属性名
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe… values)ofKeyframe方法用于在PropertyValuesHolder中设置KeyFrame对象。 propertyName:动画所要操作的属性名。values:Keyframe 的列表,PropertyValuesHolder 会根据每个 Keyframe 的设定,定时将指定的值输出给动画。

更多方法详见:
https://developer.android.google.cn/reference/android/animation/PropertyValuesHolder

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值