为了账号安全,请及时绑定邮箱和手机立即绑定

Android动画基础总结

Android动画主要分为两种,视图动画和属性动画,视图动画又分为补间动画和帧动画两种。补间动画包含透明动画(Alpha),缩放动画(Scale),平移动画(Translate),旋转动画(Rotate);帧动画是切换图片的动画;属性动画通过改变属性令视图达到动画效果。

目录

1. 视图动画

  • 补间动画
  • 帧动画

2. 属性动画

  • 值动画
  • 对象动画

3. 总结


1. 视图动画

1.1 补间动画

补间动画包含透明动画(Alpha),缩放动画(Scale),平移动画(Translate),旋转动画(Rotate),可以在控件上通过startAnimation方法启动动画,传入一个Animation类作为参数,这个类是AlphaAnimation,ScaleAnimation,TranslateAnimation,RotateAnimation的基类,通过AnimationUtils.loadAnimation方法进行创建。下面来一一解析。

  • 透明动画(Alpha)
    透明动画是一个改变视图透明度的动画。下面来创建一个透明动画:
    在res/anim里新建一个xml文件 anim_alpha
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="2000"
        android:fromAlpha="0.1"
        android:toAlpha="1" />
</set>

其中的属性duration表示动画持续时间,fromAlpha表示透明度起始值,toAlpha表示透明度的终止值。
在布局文件里放一个TextView

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hello world"
        android:textColor="#000"
        android:textSize="48dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

通过AnimationUtils.loadAnimation方法创建一个Animation,传入两个参数,第一个是页面的Context,第二个是anim文件

 var animation: Animation = AnimationUtils.loadAnimation(this, R.anim.anim_alpha)

通过startAnimation方法启动动画

 textView.startAnimation(animation)

运行代码,textView在2秒内从透明度为0.1渐变到1。

  • 缩放动画(Scale)
    缩放动画是一个改变视图大小的动画。下面来创建一个缩放动画:
    在res/anim里新建一个xml文件 anim_scale
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:duration="2000"
        android:fromXScale="1"
        android:fromYScale="1"
        android:toXScale="0.5"
        android:toYScale="0.5" />
</set>

fromXScale表示宽度起始比例,fromYScale表示高度起始比例,toXScale表示宽度终止比例,toYScale表示高度终止比例。通过startAnimation方法启动动画

var animation: Animation = AnimationUtils.loadAnimation(this, R.anim.anim_scale)
textView.startAnimation(animation)

运行代码,textView的宽高在2秒内从原来的大小缩小到一半。

  • 平移动画(Translate)
    平移动画是一个改变视图位置的动画。下面来创建一个平移动画:
    在res/anim里新建一个xml文件 anim_translate
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="2000"
        android:fromXDelta="50"
        android:fromYDelta="50"
        android:toXDelta="200"
        android:toYDelta="200" />
</set>

fromXDelta表示X轴起始位置,fromYDelta表示Y轴起始位置,toXDelta表示X轴终止位置,toYDelta表示Y轴终止位置。通过startAnimation方法启动动画

var animation: Animation = AnimationUtils.loadAnimation(this, R.anim.anim_translate)
textView.startAnimation(animation)

运行代码,textView在2秒内从x=50,y=50的位置移动到x=200,y=200的位置。

  • 旋转动画(Rotate)
    旋转动画是一个视图根据围绕中心点旋转的动画。下面来创建一个旋转动画:
    在res/anim里新建一个xml文件 anim_rotate
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate
        android:duration="2000"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="361" />
</set>

fromDegrees表示起始角度,toDegrees表示顺时针旋转角度(值为负数时逆时针旋转),pivotX表示中心点X轴坐标,pivotY表示中心点Y轴坐标,如上面 pivotX=“50%”,pivotY="50% 指的是控件的中心位置。通过startAnimation方法启动动画

var animation: Animation = AnimationUtils.loadAnimation(this, R.anim.anim_rotate)
textView.startAnimation(animation)

运行代码,textView围绕自己的中心顺时针旋转361°。

  • 组合动画
    上面举了4种动画单个启动的例子,那么如果想把他们组合在一起,该怎么用呢。举个例子:
    在res/anim里新建一个xml文件 anim_group,把上面4种动画都放进去
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000">

    <translate
        android:fromXDelta="50"
        android:fromYDelta="50"
        android:toXDelta="200"
        android:toYDelta="200" />

    <rotate
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="361" />

    <scale
        android:fromXScale="1"
        android:fromYScale="1"
        android:toXScale="0.5"
        android:toYScale="0.5" />

    <alpha
        android:fromAlpha="0.1"
        android:toAlpha="1" />
</set>

这样就得到一个组合动画,启动动画的方式也是一样

var animation: Animation = AnimationUtils.loadAnimation(this, R.anim.anim_group)
textView.startAnimation(animation)

运行代码,查看效果:

  • 状态停留
    上面举的例子都是动画播放完后视图回到原来的位置,如果视图想保持动画播放完后的状态,可以在xml文件的标签内添加属性fillAfter,true为状态停留在动画播放完后,也可以在代码中设置。如下所示:
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fillAfter="true">
···
</set>

//或者再代码中设置
animation.fillAfter = true

运行代码,查看效果:

  • 循环播放
    上面举的例子都是动画播放完就自动停止了,如果想要循环播放,可以监听动画播放,如下所示:
animation.setAnimationListener(object : Animation.AnimationListener {
            override fun onAnimationRepeat(animation: Animation?) {
            }

            override fun onAnimationEnd(animation: Animation?) {
                animation?.reset()
                animation?.start()
            }

            override fun onAnimationStart(animation: Animation?) {
            }
        })

Animation.AnimationListener可以监听动画的开始、结束、重播。如果想循环播放动画,可以在动画结束时调用reset()重置动画,然后调用start()播放。如果想要停止播放,可以在视图上调用clearAnimation()清楚动画,如下所示:

textView.startAnimation(animation)
textView.setOnClickListener {
    textView.clearAnimation()
}

运行代码,效果如下:

  • 插值器(Interpolator)
    Interpolator可以控制动画变化的速率,使动画效果能够以匀速、加速、减速等多种速率变化,默认是匀速(LinearInterpolator)。当我们需要设置Interpolator时,可以在xml文件的标签内添加属性fillAfter,true为状态停留在动画播放完后,也可以在代码中设置。如下所示:
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator">
...
</set>

//或者再代码中设置
animation.setInterpolator(AccelerateInterpolator())
//为了更好地观察效果,把持续时间改为4秒
animation.duration = 4000

AccelerateInterpolator是一个加速度插值器,动画播放起始速度变慢,但是速度越来越快,如下所示:

如果觉得效果不够明显,还可以给AccelerateInterpolator设置属性factor,factor是一个float类型的值,值越大起始速度越慢,但是速度越来越快,下面把factor设置成2f再来看一下效果:

animation.setInterpolator(AccelerateInterpolator(2f))

除了AccelerateInterpolator之外,还有很多不同的插值器,下面来一一列举:

插值器 说明
LinearInterpolator 变化速率恒定(默认)
AccelerateInterpolator 开始速率较慢,后面加速
AccelerateDecelerateInterpolator 开始和结束速率较慢,中间加速
DecelerateInterpolator 开始速率较快,后面减速
AnticipateInterpolator 开始时向后飞溅,然后向前
AnticipateOvershootInterpolator 开始时向后飞溅,然后向前,结束前冲过目标值,又回到目标值
OvershootInterpolator 开始时向前飞溅,结束前冲过目标值,又回到目标值
BounceInterpolator 结束时反弹
CycleInterpolator 动画循环播放特定的次数,速率沿着正弦曲线改变

1.2 帧动画

帧动画是一种一帧一帧播放的动画。下面举个例子:
首先我准备了4张图

在res/drawable里新建一个根属性为animation-list的anim_frame.xml,把4张图片放进去,其中oneshot属性如果为true时,动画只播放一次,如果为false则循环播放

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">

   ![![giftest13.gif](https://upload-images.jianshu.io/upload_images/2787721-b8bc65b2b25c5acd.gif?imageMogr2/auto-orient/strip)
](https://upload-images.jianshu.io/upload_images/2787721-0690977f6495c791.gif?imageMogr2/auto-orient/strip)
 <!--每张图播放100毫秒-->
    <item
        android:drawable="@drawable/pic01"
        android:duration="100" />

    <item
        android:drawable="@drawable/pic02"
        android:duration="100" />

    <item
        android:drawable="@drawable/pic03"
        android:duration="100" />

    <item
        android:drawable="@drawable/pic04"
        android:duration="100" />

</animation-list>

在布局文件中添加一个ImageView来播放帧动画

 <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

播放动画

//为ImageView设置资源
imageView.setImageResource(R.drawable.anim_frame)
//AnimationDrawable是用于创建逐帧动画的对象
var animationDrawable: AnimationDrawable
animationDrawable = imageView.drawable as AnimationDrawable
imageView.setOnClickListener {
    //点击imageView启动动画
    animationDrawable.start()
}

运行代码,查看结果


2. 属性动画

上面说到的补间动画,只提供了几种基础动画,可扩展性不强,而且在动画播放的过程中,只改变了视图的视觉效果,并没有改变他们的属性。为了弥补补间动画的缺点,在 Android 3.0 开始提供了属性动画。属性动画是通过改变对象属性实现的动画,分为值动画(ValueAnimator)和对象动画(ObjectAnimator)两种。

2.1 值动画(ValueAnimator)

值动画是通过控制对象属性的变化,不断赋值给对象的属性实现的动画。ValueAnimator有3个比较重要的方法:

  • ValueAnimator.ofInt(int values)
  • ValueAnimator.ofFloat(float values)
  • ValueAnimator.ofObject(int values)

以ofInt(int values)为例,介绍一下值动画实现方法:

1.创建值动画实例,调用ValueAnimator.ofInt(int values)设置值范围,当参数为一个时,传入的参数为结束值;当参数为两个时,第一个参数为起始值,第二个参数为结束值。

2.设置动画播放的各种属性

  • setDuration(long duration)
    设置播放时长
  • setStartDelay(long duration)
    设置延迟播放时间
  • setRepeatCount(int value)
    设置重复播放次数,value为0时不重播,value为ValueAnimator.INFINITE时无限重播
  • setRepeatMode(int value)
    设置重播模式,value为ValueAnimator.RESTART(默认)时正序重放,value为ValueAnimator.REVERSE时倒序回放

3.调用addUpdateListener()监听动画播放,通过估值器(ValueAnimator.ofInt()方法默认估值器为IntEvaluator),每变化一次,估值器就会根据比例、起始值、结束值来计算具体变化数值,然后把新的值赋给对象的属性,再重新绘制。

4.开始动画
完整代码如下

val anim = ValueAnimator.ofInt(textView.layoutParams.width, 500)
anim.setDuration(3000)//播放时间为3秒
anim.setStartDelay(0)//不延迟播放
anim.setRepeatCount(0);//不重播
anim.repeatMode = ValueAnimator.RESTART//正序重播
anim.addUpdateListener {
    var value = it.getAnimatedValue() as Int//获取变化后的值
    textView.layoutParams.width = value//新的值赋给对象的属性
    textView.requestLayout()//重新绘制
}
textView.setOnClickListener { anim.start() }

点击textView动画开始,textView会在3秒内从原来的宽度拉长到目标值500,效果如下:

ofFloat()与ofInt()大同小异,ofInt()将起始值以整形数值的形式过渡到结束值,而ofFloat()将起始值以浮点型数值的形式过渡到结束值。ofFloat()的默认估值器为FloatEvaluator。ofObject()与前两个方法不同的是,它以对象的形式将起始值过度到结束值,没有默认的估值器,只能通过自定义估值器来实现。

2.2 对象动画(ObjectAnimator)

ValueAnimator通过监听动画播放,不断获取并更新对象的属性值,实现动画效果,算是一个“手动”赋值的方式,而ObjectAnimator则是一种“自动”的方式。ObjectAnimator继承ValueAnimator,所以在用法上他们差别不大,下面举个例子:
用ObjectAnimator实现像补间动画的缩放动画那样的效果,代码如下:

val animator = ObjectAnimator.ofFloat(textView, "scaleX", 1f, 2f)
animator.setDuration(3000)
animator.start()

首先创建ObjectAnimator实例,调用ofFloat()方法并传入对应的参数,第一个参数为展示动画的对象,第二个参数为需要改变的属性,这个参数可以传入任意属性名,ObjectAnimator根据该属性名找到该对象属性的get() & set()方法进行“自动”赋值,如上面传入"scaleX",ObjectAnimator会调用scaleX的get() & set()方法对其属性进行赋值,所以如果需要采用ObjectAnimator类实现动画效果,那么需要操作的对象就必须有该属性的get() & set()方法。后面的参数为起始结束值,如果属性没有提供起始值,则调用属性的get()方法取值。因为ObjectAnimator继承ValueAnimator,所以可以跟ValueAnimator一样设置动画播放的各种属性。运行代码:

textView在3秒内从自身宽度拉长到两倍。
同样的如果要自定义对象动画,只需仿照上面例子,定义好需要操作的属性,并提供该属性的get() & set()方法。关于如何自定义对象动画,本篇就不再详解了。


3. 总结

本篇文章主要介绍了Android动画分为视图动画和属性动画两种,视图动画又分为补间动画和帧动画。帧动画主要是以一帧一帧地播放图片来展示动画;补间动画主要以透明度、缩放、选择、平移等改变视图的显示方式来展示动画;属性动画分为以“手动”或“自动”改变对象的属性值的方式来展示动画。Android动画能让app与用户交互的时候变得更有趣,而实际上在开发中也是经常会运用到动画知识,所以学好Android动画也是每一个Android开发者的必修课。本篇文章内容浅显,只说到了动画的基础知识,后面会由浅入深继续介绍Android动画,有兴趣的可以继续关注。

点击查看更多内容
3人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消