美文网首页
Android动画学习(二):基本属性动画

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

作者: 静水红阳 | 来源:发表于2021-06-08 15:25 被阅读0次

简述

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

系列文章:
Android动画学习(一):帧动画和补间动画
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轴平移动作(线性插值):

线性动画示例.jpg

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

动画属性

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

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

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

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

2. ValueAnimator

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

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());

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

那么为什么可以通过直接设置View属性就可以设置ObjectAnimator动画呢?

究其原因可以查看源码,其实ObjectAnimator的动画原理是不断的对View对象里的属性进行值的重置得到的,而像alpha这些属性都是View的基本属性,所以直接填写就能够直接更新属性,如果需要设置其他属性变化就需要重新自定义当前View的属性。

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官方文档

相关文章

  • Android属性动画完全解析

    Android属性动画完全解析(上),初识属性动画的基本用法Android属性动画完全解析(中),ValueAni...

  • Android属性动画

    版权声明:本文出自郭霖的博客Android属性动画完全解析(上),初识属性动画的基本用法Android属性动画完全...

  • Android动画之帧动画,补间动画和属性动画

    Android动画基本上可以分为视图动画和属性动画,视图动画包括帧动画和补间动画。 一.概述 通过本篇文章的学习,...

  • Android 动画锦集

    Android 动画可分为逐帧动画、补间动画、属性动画。使用传统的逐帧动画、补间动画可以实现 Android 基本...

  • Android Animation 动画介绍与详解

    一、Animation 动画属性 动画相关的属性:SET属性 二、Animation 动画类型 Android的a...

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

    简述 在上篇文章中,我们介绍了Android中的帧动画和补间动画,本篇内容则将会对Android中另一种动画——属...

  • Android学习感悟之属性动画

    本篇包括Android属性动画的基本使用,理解插值器和估值器,自定义属性动画 简介 属性动画是Android3.0...

  • Android动画总结

    本文总结常用属性方法等,详细学习可使用如下郭霖大神文章: Android属性动画完全解析(上),初识属性动画的基本...

  • Android属性动画完全解析

    Android属性动画完全解析(上)Android属性动画完全解析(中)Android属性动画完全解析(下)

  • Android知识总结

    一、Android动画 Android 属性动画:这是一篇很详细的 属性动画 总结&攻略 二、自定义View 爱哥...

网友评论

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

      本文链接:https://www.haomeiwen.com/subject/agedsltx.html