Android Animation 系列——属性动画(Property Animation)

3,948 阅读6分钟

000 属性动画简介

属性动画是 Android API level 11(Android 3.0)中添加的动画框架,功能强大,扩展性强。介绍属性动画,就需要说明三个问题:

属性是什么?

用官方的话说,Property is a field in an object。更进一步解释,这里的属性是指一个对象中具有 setter/getter 方法的变量。

属性动画可以做什么?

一般来说,动画是一种视觉效果,但是属性动画的内容要更广泛,除了做一些视觉效果之外,属性动画还可以用类似动画的方式默默改变一些数据。当然,最主要的还是实现视觉效果,包括常见的透明度、缩放、平移、旋转效果,也可以扩展出其他的属性(比如颜色)。

与之前的 View Animation 有什么区别?

View Animation 是在 API level 1 开始支持的动画框架,内容只有基本的透明度、缩放、平移、旋转,且动画的对象只能是 View。

二者的区别有以下几点:

  1. 属性动画实际改变了动画目标的属性值,比如平移一个 View,View 的位置真实发生了改变,而 View Animation仅是改变了屏幕绘制位置,真实位置不变。
  2. 属性动画可以作用于没有绘制到屏幕上的对象。
  3. 属性动画可以作用于非 View 对象,也可以制作四类基本动画之外的动画效果。
  4. View Animation 的代码量更少,效率更高。

001 相关API说明

属性动画中新添加的类主要是这些:

property animation framework.jpg

Animator

作为属性动画的基类,Animator 提供了动画最基本的属性。

仅列出一部分(我觉得)常用的。

Method Name Function
start() 开始播放
cancel() 取消动画
isRunning() 是否正在播放
addListener 添加监听回调
setTarget 设置动画目标Object
setDuration 设置播放时长,单位:毫秒
setInterpolator 设置插值器

关于插值器的内容本文暂不介绍了。

ValueAnimator

构造方法

//直接创建
    ValueAnimator valueAnimator = new ValueAnimator();
//带参数创建
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(1.0f, 2.0f);
    // ValueAnimator valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), Color.RED, Color.GREEN);
    // ...还有ofArgb,ofInt,ofPropertyValuesHolder

比起 Animator 增加的一些常用方法

Method Name Function
setStartDelay 设置动画启动延迟,单位:毫秒
addUpdateListener 添加Value更新的监听回调
setRepeatMode 设置重复播放模式,RESTART或REVERSE
setRepeatCount 设置重复播放次数
ObjectAnimtor

构造方法

//直接创建
    ObjectAnimator objectAnimator = new ObjectAnimator();
//带参数创建
    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView, "alpha", 1.0f, 0.7f);
    //...类似的构造方法有很多,就是参数不同,这些参数都可以通过setter方法设置。

ObjectAnimatior 增加了属性动画最基本的方法——设置属性。

Method Name Function
setProperty 设置动画目标属性
setPropertyName 通过name设置动画目标属性
setIntValues(int... values) 设置一系列动画参数,按顺序执行
setFloatValues(float... values) 设置一系列动画参数,按顺序执行
setObjectValues(Object... values) 设置一系列动画参数,按顺序执行
AnimatorSet

AnimatorSet 的功能就是把多个各种 Animator 对象整合成一个动画,有点类似与 ViewGroup。

Method Name Function
playTogether 多个动画一起播放
playSequentially 多个动画顺序播放

010 使用场景分析

Animator对象

ValueAnimator 的功能很单一,比较像“时间轴”,就是设置一个值,在一段时间内以某种规则变化。这也是 ObjectAnimator 实现动画的基础。

举个例子,通过 VlaueAnimator 改变 View 的颜色:

    private int mColor = Color.RED;
    public ValueAnimator valueAnimator;
//...
//...
    valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), mColor, Color.rgb(0,0,255));
    valueAnimator.setDuration(3000);
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mColor = (int) animation.getAnimatedValue();
            }
        });

onAnimationUpdate 方法中把变化后的颜色刷新到 UI 界面就行了。效果是这样的:

ValueAnimator sample.gif

相比之下 ObjectAnimator 才是属性动画中的主角,创建 ObjectAnimator 对象实现动画需要有几个要素:

  1. propertyName:要变化的属性名(String)
  2. target:具有该属性的 Object 对象
  3. values:对应属性的变化值,数据类型要和属性的类型一致

属性名接受一个 String 类型的参数,就很容易出错。可以通过输入 target 的 object 对象,在代码提示中找 setter 方法来确定属性名。View 的属性名是比较常用的,比如:alpharotationscaleXscaleYtranslationXtranslationYrotationXrotationY等。

举个例子,网络加载中可能会大量用到的一种loading动画。

    ObjectAnimator animator = new ObjectAnimator();
    animator.setPropertyName("rotation");
    animator.setTarget(ivLoading);
    animator.setFloatValues(0,360);
    animator.setDuration(900);
    animator.setRepeatMode(ObjectAnimator.RESTART);
    animator.setRepeatCount(ObjectAnimator.INFINITE);
    animator.setInterpolator(new LinearInterpolator());
    animator.start();

代码含义比较清晰,需要注意的是setInterpolator默认的插值器并不是线性的,下面给出两种效果,左侧是 LinearInterpolator ,右侧是默认的。

ObjectAnimatior Sample.gif

xml实现

xml 实现动画是一种比较合理的复用动画方式,可以有效避免在 Controller 层写过多只属于 View 层的代码。

属性动画的 xml 文件需要放在res/animator文件夹下。

语法与 View Animation 差别比较大,大概是这样子的:

xml animator(官方文档截图).png

直观感受就是比 View Animation 的 xml 实现麻烦很多,实际上由于 xml 文件的限制二者功能上差不多,应该是 View Animation 更加常用一点。(个人感受)

view.animate()

ObjectAnimator 的代码写起来不怎么好看,因为总是在 objectAnimator.xxx(),比起单独在Activity中实现某些交互效果,把简单而常用的动画效果封装成工具类会更理想一些。但是交互效果是千变万化的,总有一些独特的动画无法复用。

于是在 API level 12 中,出现了针对 View 的属性动画 ViewPropertyAnimtor。ViewProperty 中封装了 View 相关的常用动画参数的设置以及多种回调,并用 ObjectAnimator 实现了动画效果,对外提供了相当简单易懂的流式 API,使动画的代码也可以写的很爽。

使用方法:

  1. 获取 ViewPropertyAnimator 对象

ViewPropertyAnimator 没有 public 的构造方法,只能通过 View 对象的 animate() 方法获得。使用的 View 对象就是动画的 target。

ViewPropertyAnimator 对象是会重复使用的,多次调用'animate()'只会创建一个 ViewPropertyAnimator。

  1. 设置动画参数

相关的 API 名称都很明确,就不一一介绍效果了

ViewPropertyAnimator API.png

ViewPropertyAnimator API.png

  1. 设置回调(可选)

就是setListener方法。其实所有的动画都可以设置 Listener ,只是在 ViewPropertyAnimator 中更加重要,因为从 API 可以看出每一种动画只能传入一个参数,如果需要同一种动画多段执行,就只能通过监听动画结束修改参数值再开始动画。

setListener 方法接收一个 Animator.AnimatorListener 接口的实例,可以直接创建 Animator.AnimatorListener 实例实现所有方法,也可以创建 AnimatorListenerAdapter 只重写需要的方法。

ViewPropertyAnimator 的复用同样会影响 Listener,如果是同一个 View 的多个动画且不相关,需要在不需要 Listener 的动画中调用setListener(null)

这里也应该举个例子,不过没什么好的想法,姑且再写一遍 loading 动画,就当对比一下两种 API 格式吧。(kotlin代码,对比一下设置动画的 API 就好了)

ivLoadingRight.setOnClickListener {
    ivLoadingRight.animate()
            .rotationBy(360f)
            .setDuration(800)
              .setInterpolator(LinearInterpolator())
            .setListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator?) {
                    super.onAnimationEnd(animation)
                    ivLoadingRight.animate()
                            .rotationBy(360f)
                            .setDuration(800)
                              .setInterpolator(LinearInterpolator())
                            .start()
                }
            }).start()

011 结语

因为我并没有做过太多的动画效果,刚开始写的时候只想总结一下各种方法的用法和效果,然而那样就会不能避免的翻译官方文档,且内容杂乱,不易整理 demo。于是先写了一些简单的动画效果,依据实际代码反向整理了这篇文章。

文中 gif 图对应代码都在示例工程(AnimatorSample)中,地址:https://github.com/xhd-Git/Samples