标签:
属性动画从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