属性动画(一)

2017-11-08  本文已影响138人  lijiankun24

接下来的两篇文章会介绍 属性动画 相关的知识,如下图所示。本篇文章会介绍下图中绿色相关的知识。

PropertyAnimator.png

1. 简介

相比视图动画(View Animation),属性动画的功能还是非常强大的。

属性动画不仅可以对视图(View)的位置、大小、透明度、旋转进行动画操作,而且对于视图的背景颜色等属性也可以改变。

除此之外,属性动画还可以作用于视图之外的对象,比如自定义的类的对象。

一句话,只要是对象的属性都可以被属性动画所操纵。

因为还是属于动画的概念,所以需要设定一些动画相关的特性:

2. 工作原理

2.1 匀速平移动画

如下图所示,是一个简单动画的执行过程的示意图:

示意图1.png

2.2 非匀速平移动画

示意图2.png

2.3 属性值的计算原理

示意图3.png

3. 和视图动画的区别

视图动画(View animation)具有如下局限性:

属性动画则视图动画的局限性,属性动画可以作用于视图对象和非视图对象,并且可以改变任何对象的任何属性。例如,可以作用于自定义的对象的属性值,也可以作用于视图对象的背景颜色、位置大小等属性。

4. 相关 API 一览

android.animation 包下可以找到属性动画相关的所有类,视图动画相关的类定义在 android.view.animation 包下。

Class Description
ValueAnimator ValueAnimator 是属性动画的核心类,其中包含动画相关的关键信息,包括动画时间相关的细节、动画是否重复、接收更新时间的监听器等等。属性动画包括两部分:1. 计算属性值;2. 将计算得到的属性值赋予对象的属性。ValueAnimator 并不会执行第二部,所以需要开发者监听属性值的变化,并根据你自己的逻辑更新对象的属性。
ObjectAnimator ObjectAnimatorValueAnimator 类的子类,它允许开发者设置目标对象和动画操纵的属性。在计算得到新的属性值时,这个类会相应地更新对象的属性。大多数时候,使用 ObjectAnimator 都是方便的,但有时候也需要使用 ValueAnimator,因为 ObjectAnimator 有一些限制,例如 ObjectAnimator 需要目标类有相应的访问目标属性的方法
AnimatorSet AnimatorSet 提供了一种将动画合并到一起的机制,比如将多个动画同时播放、按顺序播放等。

Evaluators 用于告诉属性动画系统怎么计算属性值。它根据 Animator 提供的时间值(开始时间和结束时间),计算当前的属性值。SDK 提供以下 evaluators

Class/Interface Description
IntEvaluator 用于计算 int 类型的属性值
FloatEvaluator 用于计算 Float 类型的属性值
AnimatorSet 用于计算 ARGB 颜色类型的属性值
TypeEvaluator 用于实现自定义属性值变化的 evaluator。如果你正在作用的对象的属性不是 intfloatargb 类型的,必须实现 TypeEvaluator 的子类去定义该属性值怎么变化。

插值器 Interpolators 是用于属性值的变化率。比如是属性值是加速变化的、减速变化的、还是先加速再减速。如果默认提供的 Interpolators 不能满足开发者的需求,则可以实现 TimeInterpolator 接口自定义插值器,规定属性值该怎样从初始值变化到最终值。

Class/Interface Description
AccelerateDecelerateInterpolator 先加速再减速(默认的插值器
AccelerateInterpolator 持续加速
AnticipateInterpolator 先向反向变化一下,再向前运动
OvershootInterpolator 动画到达终点时,会先超过一点,再回缩到终点值
AnticipateOvershootInterpolator 先反向,再向前运动,超过终点值一点,再回缩到终点值
BounceInterpolator 会在目标值处弹跳
CycleInterpolator 正弦 / 余弦曲线变化率
DecelerateInterpolator 持续减速直到0
LinearInterpolator 匀速
TimeInterpolator 实现自定义插值器时需要实现的接口

4.1 ViewPropertyAnimator

ViewPropertyAnimator 是实现视图(View)类对象属性动画非常方便的类

ViewPropertyAnimator 的使用方法如下所示:

  // 表示将此按钮 translationX 值渐变为 500
  Button button = (Button) findViewById(R.id.btn);
  button.animate()
        .translationX(500)
//      .translationXBy(500) 表示将 translationX 渐变地增加 500
        .setDuration(1000)
        .start();

ViewPropertyAnimator 在实现视图类对象的位置、大小、透明度、旋转的动画的时候,是非常方便的,使用方法和上面代码非常类似,具体可以参照 API 文档和源码注释。

4.2 ObjectAnimator

ObjectAnimator 的用法也非常简单,如下代码实现了 Button 按钮从 0px 向右平移到 500px 位置的动画

    Button button = (Button) findViewById(R.id.btn);
    ObjectAnimator animator = ObjectAnimator.ofFloat(button,"translationX",0f,500f);
    animator.setDuration(800);
    animator.start();

若要正确使用 ObjectAnimator,需要注意以下几点:

  ObjectAnimator.ofFloat(targetObject, "propName", 1f)

4.3 ValueAnimator

ValueAnimator 可以在某一段时间内,对一些类型的值进行改变。通过调用它的 ofInt()ofFloat()ofObject() 工厂方法可以得到 ValueAnimator 的对象。例如:

  ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
  animation.setDuration(1000);
  animation.start();

上述代码,当调用 start() 方法动画开始时,动画的值在 1000ms 内,从 0 变化到了 100
可以为 ValueAnimator 添加监听器,监测在这段时间内动画值的变化情况,如下代码所示:

  animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

4.4 AnimatorSet

在许多情况下,一个动画需要在另一个动画开始或结束时开始执行。系统提供的 AnimatorSet 类可以将多个动画组合在一起,动画之间和同时播放,可以按顺序播放或延时播放。

同样,也可以将多个 AnimatorSet 嵌套使用。

下面是一个使用 AnimatorSet 播放组合动画的例子:

  AnimatorSet bouncer = new AnimatorSet();
  bouncer.play(bounceAnim).before(squashAnim1);
  bouncer.play(squashAnim1).with(squashAnim2);
  bouncer.play(squashAnim1).with(stretchAnim1);
  bouncer.play(squashAnim1).with(stretchAnim2);
  bouncer.play(bounceBackAnim).after(stretchAnim2);
  ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
  fadeAnim.setDuration(250);
  AnimatorSet animatorSet = new AnimatorSet();
  animatorSet.play(bouncer).before(fadeAnim);
  animatorSet.start();

4.5 PropertyValuesHolder

PropertyValuesHolder 可以实现在一个动画中,多个属性同时变化的情况,比如:一个 Button 按钮,在从小不断变大的过程中,透明度也在同时发生着变化,代码如下所示:

  Button button = (Button) findViewById(R.id.btn);
  PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);  
  PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);  
  PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1);

  ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(button, holder1, holder2, holder3)  
  animator.setDuration(800);
  animator.start();  

提到 PropertyValuesHolder,还有一个类也需要提一下 --- Keyframe(关键帧)。通过 Keyframe 可以将一个动画拆分成多个阶段。如下代码所示:

  Button button = (Button) findViewById(R.id.btn);
  // 在 0% 处开始
  Keyframe keyframe1 = Keyframe.ofFloat(0, 0);  
  // 时间经过 50% 的时候,动画完成度 100%
  Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);  
  // 时间见过 100% 的时候,动画完成度倒退到 80%,即反弹 20%
  Keyframe keyframe3 = Keyframe.ofFloat(1, 80);  
  PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("scaleX", keyframe1, keyframe2, keyframe3);

  ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(button, holder);  
  animator.start();

4.6 动画监听器

在动画运行期间,可以通过以下监听器监听动画的关键时刻:

public static interface AnimatorListener {
    // 在动画开始时被调用
    void onAnimationStart(Animator animation);

    // 在动画结束时被调用
    void onAnimationEnd(Animator animation);

    // 在动画取消时被调用
    void onAnimationCancel(Animator animation);

    // 在动画重复执行时被调用
    void onAnimationRepeat(Animator animation);
}
public static interface AnimatorPauseListener {

       //在动画暂停时被调用
       void onAnimationPause(Animator animation);

       // 在动画被重新执行时被调用
       void onAnimationResume(Animator animation);
   }
public static interface AnimatorUpdateListener {
    // 在动画刷新每一帧的时候都会被调用
    void onAnimationUpdate(ValueAnimator animation);
}
  ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
  fadeAnim.setDuration(250);
  fadeAnim.addListener(new AnimatorListenerAdapter() {
      public void onAnimationEnd(Animator animation) {
        balls.remove(((ObjectAnimator)animation).getTarget());
  }

参考资料:

官方文档

Android基础——动画(二) -- 林于卫国

HenCoder Android 自定义 View 1-7:属性动画 Property Animation(进阶篇) -- HenCoder

上一篇下一篇

猜你喜欢

热点阅读