Androids属性动画PropertyValuesHolder的使用

属性动画是在Android3.0(API 11)后提供的,相比于补间动画功能更加强大,使用起来也更加多样灵活。平时在用属性动画时用的比较多的是这种格式:

ObjectAnimator.ofFloat(...);
ValueAnimator.ofFloat(...);
这里学习记录下PropertyValuesHolder的使用。

一般用法
使用起来和上面的格式类似:

PropertyValuesHolder xHolder = PropertyValuesHolder.ofFloat("translationX", 0, 600);
PropertyValuesHolder yHolder = PropertyValuesHolder.ofFloat("translationY", 0, 600);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mIvBall, xHolder, yHolder);
animator.setDuration(1000);
animator.start();
其实就是创建两个持有对应属性在动画过程中的变量值xHolder和yHolder,在进行属性动画时可直接赋给ObjectAnimator 进行对应的动画操作。

Keyframe
Keyframe用来保存一对时间/变量的动画值,比如

Keyframe.ofFloat(float fraction, float value)
fraction:代表一个动画的时间值,范围为0-1,动画从0开始,到1结束。

value:就是在对应时间点所要设置的变量值。

Keyframe scaleFrame1 = Keyframe.ofFloat(0f, 1.0f);
Keyframe scaleFrame2 = Keyframe.ofFloat(0.5f, 2.0f);
Keyframe scaleFrame3 = Keyframe.ofFloat(1.0f, 1.0f);
PropertyValuesHolder scaleX = PropertyValuesHolder.ofKeyframe("scaleX", scaleFrame1, scaleFrame2, scaleFrame3);
PropertyValuesHolder scaleY = PropertyValuesHolder.ofKeyframe("scaleY", scaleFrame1, scaleFrame2, scaleFrame3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, scaleX, scaleY);
animator.setDuration(2000);
animator.start();
上面的属性动画在前一秒变大两倍,在第二秒又缩小到原始大小。Keyframe并没有指定某个属性变化,它只是定义了一个时间点 fraction所对应的一个变量值value,即一个动画的关键帧,而由PropertyValuesHolder.ofKeyframe()来将这个关键帧设置到对应属性上。

Keyframe也可以设置插值器Interpolator来控制上一个关键帧到当前帧的变化,但是还是不要在这上面设置插值器,不然很经常得不到想要的效果。因为插值器的时间变化是相对于整个动画时间轴,比如:scaleFrame2.setInterpolator(new AccelerateInterpolator()); 在第二个关键帧设置加速插值器。在刚开始时动画由慢加速,在到1秒的时候,你会发现整个动画突然一闪变为第二个关键帧所设的值,比如上面直接变成2倍。因为加速变化是以整个时间轴为参考,即上面的2秒,而不是在1秒就完成整个加速,所以在快到达1秒的时候动画属性变化值肯定离关键帧指定的变化值2.0f还有一段距离,在1秒的时候就直接变成指定的2.0f了。所以插值器还是设置在ObjectAnimator上比较好。

自定义属性Property
Property可以用来定义属性,举个例子:

Property mScaleX = new Property(Float.class, "scaleX") {
    @Override
    public void set(ImageView object, Float value) {
        object.setScaleX(value);
    }

    @Override
    public Float get(ImageView object) {
        return object.getScaleX();
    }
};
Property mScaleY = new Property(Float.class, "scaleY") {
    @Override
    public void set(ImageView object, Float value) {
        object.setScaleY(value);
    }

    @Override
    public Float get(ImageView object) {
        return object.getScaleY();
    }
};

这个mScaleX定义了ImageView的"scaleX"属性,mScaleY定义了ImageView的"scaleY"属性,可以用它们来设置属性动画,比如实现上个放大缩小的效果:

Keyframe scaleFrame1 = Keyframe.ofFloat(0f, 1.0f);
Keyframe scaleFrame2 = Keyframe.ofFloat(0.5f, 2.0f);
Keyframe scaleFrame3 = Keyframe.ofFloat(1.0f, 1.0f);
PropertyValuesHolder scaleX = PropertyValuesHolder.ofKeyframe(mScaleX, scaleFrame1, scaleFrame2, scaleFrame3);
PropertyValuesHolder scaleY = PropertyValuesHolder.ofKeyframe(mScaleY, scaleFrame1, scaleFrame2, scaleFrame3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, scaleX, scaleY);
animator.setDuration(2000);
animator.start();
看到这个你肯定想这有卵用,还不如上面的写法方便,但你想下我们属性是可以自定义,我们可以定义一些原先没有的属性操作方式,比如我们来定义一个旋转属性,正常旋转属性是0-360f表示转一圈,现在我们定义百分比旋转属性,0-1f 为一圈2f 为两圈,如下:

Property mRotatePercentage = new Property(Float.class, "rotatePercentage") {
    @Override
    public void set(ImageView object, Float value) {
        float rotate = value * 360f;
        object.setRotation(rotate);
    }

    @Override
    public Float get(ImageView object) {
        float rotation = object.getRotation();
        return rotation / 360f;
    }
};
下面来使用它:

Keyframe rotateFrame1 = Keyframe.ofFloat(0f, 0f);
Keyframe rotateFrame2 = Keyframe.ofFloat(0.5f, -0.5f);
Keyframe rotateFrame3 = Keyframe.ofFloat(1.0f, 1.0f);
PropertyValuesHolder rotate = PropertyValuesHolder.ofKeyframe(mRotatePercentage, rotateFrame1, rotateFrame2, rotateFrame3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mIvBall, rotate);
animator.setDuration(2000);
animator.start();
上面实现的动画为前1秒逆时针旋转180°,第二秒顺时针旋转540°,其实就是关键帧的变量值按旋转百分比来算。

如果你觉得这个没太大用处,可以看下这个开源项目:Android-SpinKit。除了能看到PropertyValuesHolder和Keyframe的一些使用方法外,还能学习自定义动画Drawable的知识,里面对画布Canvas的变化设置、图形的绘制、动画的设置进行了分层处理,很值得用来学习。

你可能感兴趣的:(Android)