属性动画关键帧:keyframe

QuibblerQuibbler 2020-09-17 约 14 分钟 2067 次阅读

属性动画关键帧:keyframe

上次介绍学习了PropertyValuesHolder《属性动画:PropertyValuesHolder》,其中还提到一个ofKeyframe()的构造方法,传入Keyframe参数。今天单独专门学习一下什么是Keyframe关键帧。

1、Keyframe

Keyframe类从API 11开始引入android.animation包中。

1.1、介绍

Keyframe包含动画的时间/值对。Keyframe类用于ValueAnimator定义动画目标在动画过程中将具有的值。随着时间从一个关键帧前进到另一个关键帧,目标对象的值将在前一个关键帧的值和下一个关键帧的值之间进行动画处理。每个关键帧还包含一个可选TimeInterpolator 对象,该对象定义了关键帧之前的时间间隔内的时间插值。

1.2、实现类:IntKeyframe、FloatKeyframe、ObjectKeyframe

Keyframe类本身是抽象的,其中有三个抽象方法没有实现getValue()、setValue()、clone()。

package android.animation;
    
    public abstract class Keyframe implements Cloneable {
	boolean mHasValue;
	boolean mValueWasSetOnStart;
	float mFraction;
	Class mValueType;
	
	...
	    
        /**
         * Gets the value for this Keyframe.
         *
         * @return The value for this Keyframe.
         */
        public abstract Object getValue();
        
        /**
         * Sets the value for this Keyframe.
         *
         * @param value value for this Keyframe.
         */
        public abstract void setValue(Object value);
        
        public abstract Keyframe clone();
        
   }

有三种实现,从类的三种of构造方法就可以发现:ofInt、ofFloat、ofObject,分别对应Keyframe的三种实现类:IntKeyframe、FloatKeyframe、ObjectKeyframe。这三个都是Keyframe的内部静态类:

/**
     * 此内部子类用于所有非int或float类型的类型。
     */
    static class ObjectKeyframe extends Keyframe {
        ...
    }
    
    /**
     * 当关键帧值是int类型时使用的内部子类。
     */
    static class IntKeyframe extends Keyframe {
        ...
    }
    
    /**
     * 当关键帧值是float类型时使用的内部子类。
     */
    static class FloatKeyframe extends Keyframe {
        ...
    }

默认包访问权限,所以开发者无法通过Keyframe的构造函数创建实例,只能通过暴露的of构造方法获取对应Keyframe实例,不错的设计思想知得学习。

2、方法

了解Keyframe类的方法,有点印象就行,真正开发的时候还得看源码找API文档。

2.1、of构造方法

特定于类型的ofXXX()工厂方法将返回特定于要存储的值类型的Keyframe的子类。这样做是为了在处理最常见的情况(例如ofFloat和 ofInt值)时提高性能。其他类型将属于更通用的Keyframe类,使用ofObject构造。

/**
     * @param fraction  float:与此关键帧相关的时间,占动画总持续时间的一部分。该值应介于0和1之间。
     * @param value     float|int|Object:当动画时间接近此关键帧中的时间时,
     *                                    对象将为其设置动画的值,而当时间经过此关键帧中的时间时则从该动画值开始。
     */

①ofFloat(float fraction, float value):使用给定的时间fraction和值value构造一个Keyframe对象。时间定义了时间,占整个动画持续时间的比例。关键帧之间的动画值将作为这些关键帧处的值之间的插值进行计算。

②ofFloat(float fraction):使用给定的时间构造一个Keyframe对象。注意没有时间点对应的值,只有动画首次开始执行的时候该值从目标对象获取(没有初始值的关键帧必须用作ObjectAnimator的一部分)

③ofInt(float fraction, int value)

④ofInt(float fraction)

⑤ofObject(float fraction, Object value)

⑥ofObject(float fraction)

⑦clone():克隆一个一模一样的Keyframe对象

注意:除非动画需要处理自定义类型或需要直接进行动画处理的数据结构(使用自定义的TypeEvaluator),否则应该优先使用float和int,因为使用这些类型的动画的运行时开销要比其他类型低。

2.2、setter和getter方法

①setFraction(float fraction):设置此关键帧的时间,占整个动画持续时间的一部分。

②setInterpolator(TimeInterpolator interpolator):设置此关键帧的可选插值器

③setValue(Object value):设置此关键帧的值

④getFraction():获取此关键帧的时间

⑤getInterpolator():获取此关键帧的可选插值器,默认是线性Interpolator

⑥getType():获取关键帧的类型

⑦getValue():获取此关键帧的值

⑧hasValue():指示此关键帧是否具有有效值(使用一个参数的of方法构造关键字是没有传入值设置的)。当ObjectAnimator第一次启动时,在内部调用此方法。通过从目标对象获取属性的值,可以为当时没有值的关键帧分配值。

3、示例

纸上得来终觉浅,光看不行。必须要实际编码使用才行,更高一层是了解其中的动画实现原理。

3.1、ofFloat

①使用ofFloat方法创建一系列关键帧

Keyframe startKeyframe = Keyframe.ofFloat(0f, 0f);
    Keyframe keyframe1 = Keyframe.ofFloat(0.1f, 10f);
    Keyframe keyframe2 = Keyframe.ofFloat(0.2f, 20f);
    Keyframe keyframe3 = Keyframe.ofFloat(0.3f, 10f);
    Keyframe keyframe4 = Keyframe.ofFloat(0.4f, 0f);
    Keyframe keyframe5 = Keyframe.ofFloat(0.5f, -10f);
    Keyframe keyframe6 = Keyframe.ofFloat(0.6f, -20f);
    Keyframe keyframe7 = Keyframe.ofFloat(0.7f, -10f);
    Keyframe keyframe8 = Keyframe.ofFloat(0.8f, 0f);
    Keyframe endKeyframe = Keyframe.ofFloat(1f, 0f);

②利用上面一系列的关键帧使用ofKeyframe()方法创建PropertyValuesHolder对象,设置rotation旋转属性

PropertyValuesHolder keyframePropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",
            startKeyframe,
            keyframe1, keyframe2, keyframe3, keyframe4,
            keyframe5, keyframe6, keyframe7, keyframe8,
            endKeyframe);

③再使用PropertyValuesHolder创建ObjectAnimator,可以设置插值器。

ObjectAnimator keyframeAnimator = ObjectAnimator.ofPropertyValuesHolder(mImageView, keyframePropertyValuesHolder);
    keyframeAnimator.setDuration(1500);
    keyframeAnimator.setInterpolator(new AccelerateInterpolator());
    keyframeAnimator.start();

3.2、ofInt

①使用ofInt()方法创建起始-中间-结束三个关键帧:中间的keyframe1关键帧设置了Interpolator,从startKeyframe到keyframe1使用该插值器。

Keyframe startKeyframe = Keyframe.ofInt(0f, 100);
    Keyframe keyframe1 = Keyframe.ofInt(0.4f, -100);
    keyframe1.setInterpolator(new BounceInterpolator());
    Keyframe endKeyframe = Keyframe.ofInt(1.0f, 100);

②再用这三个关键帧创建PropertyValuesHolder实例

PropertyValuesHolder keyframePropertyValuesHolder = PropertyValuesHolder.ofKeyframe("translateX",
            startKeyframe, keyframe1, endKeyframe);

3.2、ofObject

①使用ofObject创建三个

Keyframe startKeyframe = Keyframe.ofObject(0.0f, 'a');
    Keyframe endKeyframe = Keyframe.ofObject(1.0f, 'z');

②给其中一个关键帧添加Interpolator,这样从上一个到这一个关键帧之间的计算就会使用该插值器。

endKeyframe.setInterpolator(new AccelerateDecelerateInterpolator());

③使用ObjectKeyframe实例创建PropertyValuesHolder,使用自定义的属性

PropertyValuesHolder keyframeValuesHolder = PropertyValuesHolder.ofKeyframe("character", startKeyframe, endKeyframe);

④需要指定自定义的TypeEvaluator才能完成对自定义Object类型值的计算。

ObjectAnimator charAnimator = ObjectAnimator.ofPropertyValuesHolder(mTextView, keyframeValuesHolder);
    //传入自定义的TypeEvaluator
    charAnimator.setEvaluator(new CharacterEvaluator());
    charAnimator.setDuration(2000);
    charAnimator.start();

相关资料:

         Docs > Reference > Keyframe">Android Developers > Docs > Reference > Keyframe

        PropertyValuesHolder与Keyframe

相关推荐

WilliamChart:轻量美观的 Android 图表库实战
精选开源

WilliamChart:轻量美观的 Android 图表库实战

WilliamChart:轻量美观的 Android 图表库实战数据可视化是运动、健康、金融、统计类 App 的刚需。MPAndroidChart 功能最全但偏重复杂,WilliamChart 走的则是"轻量 + 美观 + Kotlin 原生"路线——v3 用 Kotlin 完全重写,API 极简,一行 chart.animate(dataSet) 就能把数据画成带动画的折线/柱状/环形图,开箱即

175