属性动画Property Animation的扩展用法

Interpolator的使用

Interpolator字面意思就是插入器(有道翻译),在动画中,它的主要作用是改变动画的执行速率,比如匀速,加速等一系列效果。Interpolator可以自定义实现,以下是Android系统已经为我们写好了的一些插入器:

  • AccelerateDecelerateInterpolator —— 在动画开始与结束的地方速率改变比较慢,在中间的时候加速
  • AccelerateInterpolator ——————– 在动画开始的地方速率改变比较慢,然后开始加速
  • AnticipateInterpolator ——————— 开始的时候向后然后向前甩
  • AnticipateOvershootInterpolator ——– 开始的时候向后然后向前甩一定值后返回最后的值
  • BounceInterpolator ———————— 动画结束的时候弹起,类似皮球掉地上弹起的效果
  • CycleInterpolator ————————— 动画循环播放特定的次数,速率改变沿着正弦曲线
  • DecelerateInterpolator ——————— 在动画开始的地方快然后慢
  • LinearInterpolator ————————- 以常量速率改变,即匀速
  • OvershootInterpolator ——————- 向前甩一定值后再回到原来位置

具体的使用比较简单,在Java代码中调用动画对象的setInterpolator()方法传入Interpolator对象:

1
2
3
4
5
6
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mImageView, "translationY", mImageView.getTranslationY(), 400);
// 设置动画时长
objectAnimator.setDuration(5000);
// 设置弹起效果
objectAnimator.setInterpolator(new BounceInterpolator());
objectAnimator.start();

在xml中使用android:interpolator 属性:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<!-- 将alpha的值从1过渡到0,时长1秒 -->
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType"
android:duration="1000"
android:propertyName="alpha"
android:interpolator="@android:anim/linear_interpolator"/>

TypeEvaluator的用法

TypeEvaluator翻译为类型估值算法,又称估值器,它的作用是通过起始值、结束值以及插值器返回值来计算在该时间点的属性值应该是多少,也就是控制动画实际运动轨迹,系统给我们提供IntEvaluator(针对整型属性)、FloatEvaluator(针对浮点型属性)以及ArgbEvaluator(针对Color属性),如果想根据某个属性TYPE来实现动画,但是这个Type又不是Android系统内置的,这个时候就需要创建一个自己的evaluator来实现了,并且新创建的type必须实现接口TypeEvaluator。Android系统内置的type有int,float和color,他们对应的evaluator是IntEvaluator、FloatEvaluator和ArgbEvaluator。接口TypeEvaluator内只有一个方法,用来计算要实现动画属性的值。以下是TypeEvaluator接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators
* allow developers to create animations on arbitrary property types, by allowing them to supply
* custom evaluators for types that are not automatically understood and used by the animation
* system.
*
* @see ValueAnimator#setEvaluator(TypeEvaluator)
*/
public interface TypeEvaluator<T> {
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
* calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue The start value.
* @param endValue The end value.
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
public T evaluate(float fraction, T startValue, T endValue);
}

接口只有一个方法evaluate()返回了一个泛型,方法的第一个参数是估值小数,也就是插值器计算出来的当前属性改变的百分比,第二个参数是动画开始值,第三个参数是动画的结束值。

我们看看IntEvaluator的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* This evaluator can be used to perform type interpolation between <code>int</code> values.
*/
public class IntEvaluator implements TypeEvaluator<Integer> {
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue The start value; should be of type <code>int</code> or
* <code>Integer</code>
* @param endValue The end value; should be of type <code>int</code> or <code>Integer</code>
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}

很明显,其在evaluate()方法中进行了数值的转换,并返回了结果,所以我们只需照着做就行。

比如,我现在需要让一个图片实现抛物线运动,则可以借助自定义的TypeEvaluator实现,首先定义一个坐标类Point,里面包含x轴跟y轴,以及对应的setter,getter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* 坐标点,用于控制动画的位置
* Created by zhangyongming on 2017/1/11.
*/
public class Point {
private float x;
private float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
}

然后是自定义的PointEvaluator类,这里我们获取动画执行时的x轴跟y轴的坐标,并返回一个Point对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Point的估值器
* Created by zhangyongming on 2017/1/11.
*/
public class PointEvaluator implements TypeEvaluator<Point> {
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
float resultX = startValue.getX() + (endValue.getX() - startValue.getX()) * fraction;
float resultY = startValue.getY() + (endValue.getY() - startValue.getY()) * fraction;
return new Point(resultX,resultY);
}
}

接下来就是给ImageView使用了:

1
2
3
4
5
6
7
8
9
10
11
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(), new Point(50, 50), new Point(500, 500));
valueAnimator.setDuration(2000);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Point point = (Point) valueAnimator.getAnimatedValue();
mImageView.setX(point.getX());
mImageView.setY(point.getY());
}
});

基本上的实现思路就是这样的。

PropertyValuesHolder的用法

propertyValuesHolder可以用于动画的组合执行,使用起来很简单,如下示例:

1
2
3
4
PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f);
PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0f, 1f);
PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0f, 1f);
ObjectAnimator.ofPropertyValuesHolder(mImageView, alpha, scaleX, scaleY).setDuration(2000).start();

这样就能很容易地实现三个动画的组合播放了。

ViewPropertyAnimator的用法

ViewPropertyAnimator可以用一种很简便的方式让控件执行动画,该类提供了链式调用进行多个属性同时变化的动画,更加简洁方便我们操作组合动画(多个属性同时进行变化),它可以为同时动画提供更好的性能。ViewPropertyAnimator在动画进行的时候只对多个属性的变化进行一次invalidate调用,而不是对变化每个属性进行调用(n个ObjectAnimator就会进行n次属性变化,就有n次invalidate)。当然这个类的调用方式更方便,调用对应属性方法传一个属性值就可以自动实现动画。每个属性方法都有两种调用形式,例如 alpha(float value) 和alphaBy(float value),前者是变化到多少,后者是变化多少。

ViewPropertyAnimator没用提供公开的构造方法,通过调用view的animate()获取引用。

总而言之:

  • ViewPropertyAnimator操作View对象的。
  • 提供链式调用设置多个属性动画,这些动画同时进行的。
  • 更好的性能,多个属性动画是一次同时变化,只执行一次UI刷新。
  • 每个属性提供两种类型方法设置。
  • ViewPropertyAnimator只能通过View的animate()获取引用进行设置。

比如让一个图片控件在1秒内由透明变为不透明:

1
mImageView.animate().alpha(0f).setDuration(1000);

是不是很方便?当然也可以使用插入器,同样只需要在后面继续调用setInterpolator()方法即可:

1
mImageView.animate().alpha(0f).setDuration(1000).setInterpolator(new LinearInterpolator());

只需要使用连缀的方式使用就行,大大简化了代码,如果需要实现组合动画也一样,同样使用连缀的方式:

1
mImageView.animate().alpha(0f).rotation(360).setDuration(1000).setInterpolator(new LinearInterpolator());

可以看出我们不需要调用start()方法,这是由于ViewPropertyAnimator在将我们所有的连缀的方法初始化之后会为我们调用start()方法,使动画执行。

如果觉得本文对你有帮助,请支持我!