标签:
属性动画从API 11引入,比视图动画更加强大,用官方的话说,属性动画可以改变任何事物。而视图动画仅仅是动画。视图动画基类是android.view.animation.Animation,而属性动画基类是android.animation.Animator
如下是属性动画的继承关系:
属性动画中,属性值的计算过程如下图:
由图可见,要将时间变量转换成最终改变的属性值,需要三步。
第一:计算出动画时间的分数,根据消耗的时间占用总时间的比,得到0到1的一个分数。
第二:计算插值(动画完成率),根据上一个值,计算出动画的完成度,可以大于1,也可以小于0。
第三:计算需要的属性值,使用合适的TypeEvaluator计算出需要的属性值。
完成了上面3步计算,最后使用得到的属性值来改变需要改变的对象,就可以得到想要的动画了。
首先,先来了解属性动画中两个常用类ValueAnimator以及ObjectAnimator的用法。以及PropertyValuesHolder和Keyframe。
ValueAnimator并不会直接操作任何属性,而仅仅是回调,让开发者自己做处理。
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//...
}
});
animation.setInterpolator(new LinearInterpolator());
animation.start();
如上,在onAnimationUpdate这个回调方法中,可以做出相应的操作,该方法会在每一个动画帧的时候回调。对属性等做出改变,就能产生对应的动画。
常用的两个方法如下:
public static ValueAnimator ofInt(int… values)
public static ValueAnimator ofFloat(float… values)
可以看到接收的是可变参数,意思是说,值可以在多个值之间变动,而不仅仅局限于从一个变化到另一个。
另外的常用方法如下:
| 方法名 | 描述 |
|---|---|
| setDuration(long duration) | 设置动画时长,单位毫秒 |
| getAnimatedValue() | 返回动画的值 |
| start() | 开始动画 |
| setRepeatCount(int value) | 重复次数,INFINITE代表无限 |
| setRepeatMode(int value) | 重复模式,有RESTART(从头开始)和REVERSE(倒序开始) |
| cancel() | 取消动画 |
ValueAnimator拥有两种监听器,其中AnimatorUpdateListener监听动画的实时变化,在上面的代码中也有提现,另外还有一个监听器AnimatorListener,主要用于监听动画的start,end,cancle,repeart状态。
值得特别注意的是ofObject(TypeEvaluator evaluator, Object... values)方法,该方法接收一个TypeEvaluator以及可变参数Object,从上面的属性动画属性值计算过程图可以看出,经过加速器(插值器)的计算后,就需要TypeEvaluator将值转换成需要的值,那么这里就需要它返回对应的对象。这里需要通过自定义TypeEvaluator来实现。
public interface TypeEvaluator<T> {
public T evaluate(float fraction, T startValue, T endValue);
}
继承TypeEvaluator,并指定合适的泛型,随后通过evaluate方法返回指定对象。同时通过ValueAnimator的setEvaluator(TypeEvaluator value)方法指定自定义的TypeEvaluator即可。
ValueAnimator并不能直接操作属性,需要在回调中自行处理,而ValueAnimator的子类ObjectAnimator则做了改进,可以直接更改属性值,可以省下一些代码。
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView,"alpha",1,0,1);
animator.setDuration(1000);
animator.start();
ObjectAnimator的ofFloat方法,和ValueAnimator有所不同,多了一个参数,传值为alpha,其实这个参数是需要更改的属性名。该属性必须有set方法,并按照驼峰式的命名方式命名。每次回调,会根据反射自定将新的属性值使用set方法设置给对应属性。从而产生动画。
其他的用法基本和ValueAnimator用法类似。
这个类主要用于保存动画所需的属性值,通过ValueAnimator以及ObjectAnimator的ofFloat等方法构造的动画,在内部也是将参数封装为PropertyValuesHolder实例来保存所需的属性值。因此,使用上诉两个类构造动画的时候,也可以使用ofPropertyValuesHolder(PropertyValuesHolder... values) 方法直接传入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)
前三个方法和ObjectAnimator的使用基本相同,而第四个方法是ObjectAnimator没有的,它接收Keyframe的实例。
Keyframe是关键帧,关键帧的概念有点类似于补间动画,也就是指定一些关键的帧,然后让系统自动补齐其余的帧。它也有ofInt,ofFloat,ofObject方法来构建实例,使用关键帧创建动画的示例代码如下:
Keyframe frame0 = Keyframe.ofFloat(0f, 1);
Keyframe frame1 = Keyframe.ofFloat(0.5f, 2);
frame1.setInterpolator(new AnticipateOvershootInterpolator());
Keyframe frame3 = Keyframe.ofFloat(1, 3);
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("scaleX", frame0, frame1, frame3);
PropertyValuesHolder frameHolder2 = PropertyValuesHolder.ofKeyframe("scaleY", frame0, frame1, frame3);
Animator animator = ObjectAnimator.ofPropertyValuesHolder(mTextView, frameHolder,frameHolder2);
animator.setDuration(5000);
animator.setInterpolator(new LinearInterpolator());
animator.start();
public static Keyframe ofFloat(float fraction, float value)有两个参数,第一个代表当前动画的时间进度,第二个代表动画的完成率,也就是经过插值器计算后得到的值。理所当然,它就可以设置插值器,可以看到上面的代码,frame1设置的插值器,那么这个插值器实际是在frame0到frame1之间起作用的,也就是说,插值器在当前帧和前一帧之间起作用。
如果animator和frame都设置了插值器,那么谁会起作用呢,经过如上代码的实验,frame设置了插值器后,将不受animator插值器的影响。
从图中可以看出,很明显有Anticipate加速器的效果,而不是animator设置的LinearInterpolator加速器。
AnimatorSet可以实现组合动画,将几个动画组合在一起播放。有playSequentially和playTogether两种方式。
public void playSequentially(Animator... items);
public void playSequentially(List<Animator> items);
都是接收可变参数,或者列表。
playSequentially是将动画逐个播放,而playTogether是将动画一起播放。
如果需要更加自由的控制动画播放顺序,需要使用AnimatorSet.Builder。
AnimatorSet animatorSet = new AnimatorSet();
AnimatorSet.Builder builder = animatorSet.play(animator1);
builder.with(animator2);
builder通过Animator的play方法生成,随后使用builder的相关方法来控制动画的顺序。相关方法如下:
//和play动画一起执行
public Builder with(Animator anim)
//先于play动画执行
public Builder before(Animator anim)
//后于play动画执行
public Builder after(Animator anim)
//延迟执行,单位毫秒
public Builder after(long delay)
AnimatorSet也有监听器,如下:
public static interface AnimatorListener {
/**
* 当AnimatorSet开始时调用
*/
void onAnimationStart(Animator animation);
/**
* 当AnimatorSet结束时调用
*/
void onAnimationEnd(Animator animation);
/**
* 当AnimatorSet被取消时调用
*/
void onAnimationCancel(Animator animation);
/**
* 当AnimatorSet重复时调用,由于AnimatorSet没有设置repeat的函数,所以这个方法不会被调用
*/
void onAnimationRepeat(Animator animation);
}
监听器的使用和之前的Animator基本一致。
值得注意的是AnimatorSet还有3个方法:
public AnimatorSet setDuration(long duration);
public void setInterpolator(TimeInterpolator interpolator)
public void setTarget(Object target)
值得注意的是:这3个方法调用以后,都会覆盖掉AnimatorSet中的单个动画的设置。
API 12才引入,使用ViewPropertyAnimator可以方便的改变view的多个属性从而添加动画,并且代码更加连贯。
mTextView.animate().alpha(0.5f).rotationX(30).setDuration(2000).start();
可以看到,透明度变化和x轴旋转以及时间设置等,都通过一句话完成,整个过程更加流畅和方便。
标签:
原文地址:http://blog.csdn.net/cquwentao/article/details/51363089