Android动画分析详解(二)属性动画、TimeInterpolator插值器、TypeEvaluator估值器

属性动画

属性动画是在Android3.0后新增的效果,功能十分强大,它可以操作任意对象的属
性,而不仅仅只是View对象。在指定的时间内将对象的属性值变为另一个属性值。属性动画中有AnimatorSet,ValueAnimator,ObjectAnimator等。通过利用这些类实现绚丽的动画效果

改变View的透明度

ObjectAnimator alpha = ObjectAnimator.ofFloat(tv, "alpha", 1, .1f);
alpha.setDuration(5000);
alpha.setRepeatCount(ObjectAnimator.INFINITE);
alpha.setRepeatMode(ObjectAnimator.REVERSE);
alpha.start();

ObjectAnimator和ValueAnimator常用属性,ObjectAnimator继承自ValueAnimator

  • duration:动画时长
  • repeatCount:动画播放的重复次数,默认为0, INFINITE代表无限重复
  • repeatMode:重复播放的模式(RESTART,REVERSE),RESTART:每次重复播放都重新开始,REVERSE:重复播放时逆序播放,就是按照0-1,1-0,0-1…这样的模式

在ObjectAnimtoar类的静态方法中,有ofInt(),ofFloat(),ofArgb()..等表示操作的属性分辨是int,float,颜色类型

ofFloat()方法原型:
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)

  1. target:操作的对象
  2. propertyName:操作的属性名称
  3. values:属性变化的值,可变参数类型

属性动画可以在XML布局文件中设置,布局文件处于/res/animator目录下。

android:ordering="sequentially">
android:duration="300"
android:repeatCount="infinite"
android:startOffset="100"
android:repeatMode="reverse"
android:valueTo="100"
android:valueType="intType" />

  • set标签代表的是AnimatorSet类,表示的是属性动画集合
  • ordering:表示集合内的动画的播放顺序 sequentially:按动画的定义顺序播放 together:一起播放,默认为together
  • startOffset:动画开始前的延时时间

    其他属性在上面已经介绍了就不在多加阐述。

在代码中使用XML布局文件中的属性动画:
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.animator_layout);
animatorSet.setTarget(tv);
animatorSet.start();

虽然两种方式都可以使用属性动画,还是建议在代码中创建,一个原因是创建比较简洁, 第二个是因为属性动画操作的是View的属性,而View的大部分属性其实是没办法事先确定好的,要依赖动态的创建属性动画。

插值器和估值器

TimeInterpolator时间插值器(插值器的顶级接口)

作用:根据当前时间的流逝百分比计算出属性值变化的百分比,Android系统已经预设了一些常用的插值器:LinearInterpolator(线性插值器,匀速动画),AccelerateDecelerateInterpolator(加速减速插值器,先慢再快最后慢的动画效果),AccelerateInterpolator(加速插值器),DecelerateInterpolator(减速插值器)

TypeEvaluator估值器/类型估值算法

作用:根据当前属性变化的百分比计算出改变后的属性值,Android系统预设的常用估值器有:IntEvaluator(整型估值器),FloatEvaluator(浮点型估值器),ArgbEvaluator(颜色估值器)

举个实际的例子:

将View的alpha属性在5000毫秒内从1.0变为0.0

ObjectAnimator alpha = ObjectAnimator.ofFloat(tv, "alpha", 1, 0f);
alpha.setDuration(5000);
alpha.setInterpolator(new LinearInterpolator());
alpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedFraction = animation.getAnimatedFraction();
float animatedValue = (float) animation.getAnimatedValue();
}
});
alpha.start();

  • animation.getAnimatedFraction():获取动画播放的进度[0,1]
  • animation.getAnimatedValue():动画播放过程中对应的属性值变化后的值

这是使用了线性插值器,默认使用AccelerateDecelerateInterpolator(加速减速插值器)
可以通过给动画添加AnimatorUpdateListener监听动画过程中属性值的变化。
关于动画的监听除了AnimatorUpdateListener,还有AnimationListener

public static interface AnimationListener {
void onAnimationStart(Animation animation); 动画开始
void onAnimationEnd(Animation animation); 动画结束
void onAnimationRepeat(Animation animation); 动画重复
}

使用属性动画操作View属性需要的条件

属性动画可以操作任意的属性,前提是要满足两个条件,不然要不没效果,要不程序直接Crash

1.被操作的属性必须要有get及set方法,即如果操作x属性,要提供getX()和setX(),如果不满足,程序直接Crash

2.被操作的属性在进行属性动画改变时,必须能通过某种方式体现出来,例如可以引起UI的变化,如果不满足该条件,动画没有效果。

示例:

假设我们要用属性动画的方式改变TextView的width属性

ObjectAnimator.ofInt(tv, "width", 200).setDuration(2000).start();

这里会发现程序运行后没有效果,这里其实就没有同时满足上述的两个条件,width属性确实有提供getWidth()及setWidth()方法,getWidth()是View提供的方法,但是setWidth()却不是View提供的,他只是TextView提供的一个方法,调用setWidth无法改变宽度,所以这里只满足了条件1导致动画效果不生效。

对于以上的问题官方也给了三种解决方案:

  • 给你要操作的对象属性加上get及set方法,如果有权限
  • 通过新建一个包装类间接的为属性提供get及set方法
  • 通过ValueAnimator,监听动画的过程,自己去实现属性的改变

这里需要说明的是因为我们操作的大部分属性都是系统提供的,我们是没有权限去改变,所以一般采用第二、三种方案。

采用第二种方式改变width:

public class ViewWrapper {
private View target;

public ViewWrapper(View source) {
    this.target = source;
}
public int getWidth() {
    return target.getLayoutParams().width;
}
public void setWidth(int width) {
    target.getLayoutParams().width = width;
    target.requestLayout();
}

}

使用装饰类:
ViewWrapper viewWrapper = new ViewWrapper(tv);
ObjectAnimator.ofInt(viewWrapper, "width", 200).setDuration(2000).start();

你可能感兴趣的:(android)