属性动画

一 概述

属性动画从API 11引入,比视图动画更加强大,用官方的话说,属性动画可以改变任何事物。而视图动画仅仅是动画。视图动画基类是android.view.animation.Animation,而属性动画基类是android.animation.Animator

如下是属性动画的继承关系:

这里写图片描述

属性动画中,属性值的计算过程如下图:

这里写图片描述

由图可见,要将时间变量转换成最终改变的属性值,需要三步。

第一:计算出动画时间的分数,根据消耗的时间占用总时间的比,得到0到1的一个分数。

第二:计算插值(动画完成率),根据上一个值,计算出动画的完成度,可以大于1,也可以小于0。

第三:计算需要的属性值,使用合适的TypeEvaluator计算出需要的属性值。

完成了上面3步计算,最后使用得到的属性值来改变需要改变的对象,就可以得到想要的动画了。

首先,先来了解属性动画中两个常用类ValueAnimator以及ObjectAnimator的用法。以及PropertyValuesHolderKeyframe

二 ValueAnimator

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,主要用于监听动画的startendcanclerepeart状态。

值得特别注意的是ofObject(TypeEvaluator evaluator, Object... values)方法,该方法接收一个TypeEvaluator以及可变参数Object,从上面的属性动画属性值计算过程图可以看出,经过加速器(插值器)的计算后,就需要TypeEvaluator将值转换成需要的值,那么这里就需要它返回对应的对象。这里需要通过自定义TypeEvaluator来实现。

public interface TypeEvaluator<T> {

public T evaluate(float fraction, T startValue, T endValue);

}

继承TypeEvaluator,并指定合适的泛型,随后通过evaluate方法返回指定对象。同时通过ValueAnimatorsetEvaluator(TypeEvaluator value)方法指定自定义的TypeEvaluator即可。

三 ObjectAnimator

ValueAnimator并不能直接操作属性,需要在回调中自行处理,而ValueAnimator的子类ObjectAnimator则做了改进,可以直接更改属性值,可以省下一些代码。

ObjectAnimator animator = ObjectAnimator.ofFloat(imageView,"alpha",1,0,1);  
animator.setDuration(1000);  
animator.start();  

ObjectAnimatorofFloat方法,和ValueAnimator有所不同,多了一个参数,传值为alpha,其实这个参数是需要更改的属性名。该属性必须有set方法,并按照驼峰式的命名方式命名。每次回调,会根据反射自定将新的属性值使用set方法设置给对应属性。从而产生动画。

其他的用法基本和ValueAnimator用法类似。

四 PropertyValuesHolder&Keyframe

这个类主要用于保存动画所需的属性值,通过ValueAnimator以及ObjectAnimatorofFloat等方法构造的动画,在内部也是将参数封装为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设置的插值器,那么这个插值器实际是在frame0frame1之间起作用的,也就是说,插值器在当前帧和前一帧之间起作用。

如果animator和frame都设置了插值器,那么谁会起作用呢,经过如上代码的实验,frame设置了插值器后,将不受animator插值器的影响。

这里写图片描述

从图中可以看出,很明显有Anticipate加速器的效果,而不是animator设置的LinearInterpolator加速器。

五 AnimatorSet

AnimatorSet可以实现组合动画,将几个动画组合在一起播放。有playSequentiallyplayTogether两种方式。

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通过Animatorplay方法生成,随后使用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中的单个动画的设置。

六 ViewPropertyAnimator

API 12才引入,使用ViewPropertyAnimator可以方便的改变view的多个属性从而添加动画,并且代码更加连贯。

mTextView.animate().alpha(0.5f).rotationX(30).setDuration(2000).start();

可以看到,透明度变化和x轴旋转以及时间设置等,都通过一句话完成,整个过程更加流畅和方便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值