Android动画学习(二):基本属性动画

时间:2021-7-21 作者:qvyue

简述

在上篇文章中,我们介绍了Android中的帧动画和补间动画,本篇内容则将会对Android中另一种动画——属性动画进行简单介绍。
属性动画的功能非常强大,可以满足我们平常对动画的开发。

和补间动画的区别

上篇内容中,我们讲述了补间动画的简单实现,补间动画主要能够对View实现如下几种操作:

  1. 平移
  2. 旋转
  3. 缩放
  4. 淡入淡出效果

但是补间动画也就只能实现上述4种操作或者是几种操作的混合内容,不能够实现一些其他的动画操作:例如对view的背景颜色进行动画变化。而相对更加灵活的属性动画则可以实现上述功能。

除此之外,补间动画和属性动画还有一个重要的区别:
补间动画只会改变View的显示效果,不会去改变View的真正属性;而属性动画则会确实的改变View的属性

举例来说,当前实现一个平移动画使View1从位置A移动到B。

如果采用补间动画,我们可以看到视觉效果上View1从A移动到了B,当时当你点击在B处的View1时却不会触发View1的点击事件,点击事件的触发仍然是在A处触发的。

如果采用属性动画,则View1的属性会直接变动,包括其点击事件都会在B处触发。

上述就是对于属性动画的基本介绍了,接下来我会介绍一下属性动画的简单使用。

属性动画

1. 属性动画参数

动画原理

在介绍属性动画使用之前,我们先来分析一下动画特性和原理进行分析。

动画的工作原理是不断的去刷新视图,当以特定的高帧频率刷新视图时,在视觉上就会连续效果,和电影原理是一样的。

属性动画同样如此,如下图,实现一个View的X轴平移动作(线性插值):

Android动画学习(二):基本属性动画
线性动画示例.jpg

可以看到是视图以每10ms就移动10px(线性插值,动画速度恒定),视图以每10ms就刷新一次。

动画属性

从上面的实例中,我们可以总结下定义一个动画所需要的基本属性:

  1. 动画时长:动画的播放时长
  2. 动画对象:动画应用的对象View
  3. 动画播放逻辑:淡入淡出,缩放,平移等动画的实际播放动作,包括动画播放的先后顺序
  4. 重复和计数:动画是否能够重复,重复次数。
  5. 时间插值:动画播放快慢频率控制。
属性动画核心类

属性动画同样需要这几个条件,主要涉及的核心类包括如下三个:

类名 说明
ValueAnimator 属性动画核心类能够实现属性动画的核心功能,也计算添加动画效果属性的值
ObjectAnimator ValueAnimator子类,用于实现对指定view的动画
AnimatorSet 实现组合动画的类

2. ValueAnimator

ValueAnimator是属性动画中的核心类,它继承自Animator类,类图如下(截自官方文档):

Android动画学习(二):基本属性动画
ValueAnimator类图.jpg

类图上可以看到ValueAnimator的几个核心属性和方法:

属性或方法 名称
TimeInterpolator 动画插值
TypeEvaluator 动画评估,指定动画的变化
duration 动画时长
start() 播放动画
startPropertyValue 起始值
endPropertyVaule 结束值
TimeInterpolator

动画插值,决定动画执行的快慢。其中Android SDK中提供了一些常见的插值器,在android.view.animation中,具体内容如下:

说明
AccelerateDecelerateInterpolator 该插值器的变化率在开始和结束时缓慢但在中间会加快。
AccelerateInterpolator 该插值器的变化率在开始时较为缓慢,然后会加快。
AnticipateInterpolator 该插值器先反向变化,然后再急速正向变化。
AnticipateOvershootInterpolator 该插值器先反向变化,再急速正向变化,然后超过定位值,最后返回到最终值。
BounceInterpolator 该插值器的变化会跳过结尾处。
CycleInterpolator 该插值器的动画会在指定数量的周期内重复。
DecelerateInterpolator 该插值器的变化率开始很快,然后减速。
LinearInterpolator 该插值器的变化率恒定不变。
OvershootInterpolator 该插值器会急速正向变化,再超出最终值,然后返回。
TypeEvalutaor

TypeEvalutaor指定动画的变化内容,常见的内容有如下几种:

类/接口 说明
IntEvalutor 计算Int的值变化
FloatEvaluator 计算Float属性的值变化
ArgbEvaluator 计算颜色的值变化
TypeEvaluator 动画变化,可以实现此接口自定义内容
ValueAnimator使用

在ValueAnimator内部使用了一种时间循环机制来计算值与值的动画过度,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就可以完成从初始值平滑的过度到结束值这样的效果。

ValueAnimator的使用并不复杂,截取官方文档上的示例,实现一个在1000ms内从0过度到100的一个数值动画,可以如下代码实现:

    ValueAnimator.ofFloat(0f, 100f).apply {
        duration = 1000
        start()
    }

但是在在执行了上述代码后,却没有看到显示效果,原因是由于这是一个数值动画,不涉及到View的变化,因此如果要获取到动画运行的状态,必须要借助监听器AnimatorUpdateListener来实现,如下:

    ValueAnimator.ofObject(...).apply {
        ...
        addUpdateListener { 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.
            textView.translationX = updatedAnimation.animatedValue as Float
        }
        ...
    }

对于ofObject方法需要注意的是此方法的参数可以是多个,我们可以通过设置多个参数实现多个动画节点,如ValueAnimator.ofFloat(0f, 100f,20f,90f),则就会实现从0到100,再到20,最后到90的动画效果。

3. ObjectAnimator

相对于ValueAnimator实现数值的动画过度,能实现View动画的ObjectAnimator类应该我们经常使用到属性动画类。但是实际上ObjectAnimatorValueAnimator的一个子类,其动画生成机制是一样的。

其使用也是比较简单的,示例如下,实现一个文本控件平移动画:

 ObjectAnimator.ofFloat(textView, "translationX", 100f).apply {
        duration = 1000
        start()
    }

同样的,我们也能够实现透明度,旋转,缩放的动画效果,如下:

   /**
     * 透明度属性动画
     */
    private fun setAlphaProAnimation(v: View?) {
        if (v != null) {
            val anim = ObjectAnimator.ofFloat(v, "alpha", 0f, 1f, 0f, 1f)
            anim.duration = 3000
            anim.start()
        }
    }

    /**
     * 缩放属性动画
     */
    private fun setScaleProAnimation(v: View?) {
        if (v != null) {
            val anim = ValueAnimator.ofFloat(0f, 1f)
            anim.duration = 3000
            anim.addUpdateListener {
                val value = it.animatedValue
                v.scaleX = value as Float
                v.scaleY = value as Float
            }
            anim.start()
        }
    }

    /**
     * 平移属性动画
     */
    private fun setTranProAnimation(v: View?) {
        if (v != null) {
            val anim = ObjectAnimator.ofFloat(v, "translationX", 0f, 100f)
            anim.duration = 1000
            anim.start()
        }
    }

    /**
     * 旋转属性动画
     */
    private fun setRotationProAnimation(v: View?) {
        if (v != null) {
            val anim = ObjectAnimator.ofFloat(v, "rotation", 0f, 90f)
            anim.duration = 1000
            anim.start()
        }
    }

看到这里,大家可以比较疑惑这个属性的值是从怎么地方获取的,如rotationalpha这些值,实际上这些值是在View的属性里去获取到的,去查询到当前属性名的getset方法,从View的代码中可以看到这些常见的属性名称:

stream.addProperty("drawing:alpha", getAlpha());

相应的,其他常见属性也是如此查询到的。

4. AnimatorSet组合动画

独立的动画实现的效果是比较有限的,因此在平常的开发过程中将多个动画组合到一起播放是经常碰到的问题。Android SDK中自然也是有方法能够实现组合动画:AnimatorSet

AnimatoeSet类提供了一个play()方法用来播放动画,同时也提供了用来对动画顺序进行管控的方法:

  1. after(Animator anim):将现有动画anim插入到传入的动画之后执行
  2. before:将现有的动画插入到传入的动画之前执行
  3. with:将现有的动画和传入的动画同时执行
  4. after(long time):将 现有的动画延迟指定的时间后执行,单位ms

示例如下:

    val bouncer = AnimatorSet().apply {
        play(bounceAnim).before(squashAnim1)
        play(squashAnim1).with(squashAnim2)
        play(squashAnim1).with(stretchAnim1)
        play(squashAnim1).with(stretchAnim2)
        play(bounceBackAnim).after(stretchAnim2)
    }
    val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
        duration = 250
    }
    AnimatorSet().apply {
        play(bouncer).before(fadeAnim)
        start()
    }

上述示例中的动画执行顺序如下:

  1. 播放动画bounceAnim
  2. 同时播放动画squashAnim1squashAnim2,stretchAnim1,stretchAnim2
  3. 播放bounceBackAnim.
  4. 播放fadeAnim.

5. 动画监听器

可以使用下述监听器来监听动画播放期间的重要事件。

  • Animator.AnimatorListener
    
    • onAnimationStart() – 在动画开始播放时调用。
    • onAnimationEnd() – 在动画结束播放时调用。
    • onAnimationRepeat() – 在动画重复播放时调用。
    • onAnimationCancel() – 在动画取消播放时调用。取消的动画也会调用
    • onAnimationEnd(),动画结束调用。
  • ValueAnimator.AnimatorUpdateListener
    
    • onAnimationUpdate() – 对动画的每一帧调用。

总结

本文对属性动画的概念和属性进行了简单的说明,可以实现和简单的平移、旋转、缩放和透明度控制的简单组合动画,自定义动画后续会进行探讨学习。

参考文章

Google官方文档

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。