前言
动画是生活中必不可少的东西,只要在向用户传递信息或展示内容都会用到动画,接下来我们讲讲在 Android
中的一些动画,这些动画主要分为 4
种,分别是 帧动画
, 矢量动画
, 补间动画
, 属性动画
。
一.帧动画
帧动画,顾名思义就是通过一张张图片通过快速切换而到达的一种视觉效果,看起来像图片中的物体动起来一般,我们平常说的 60
帧,120帧
,指的就是一秒钟播放 60
张图片或 120
张图片。
1.在xml文件中添加图片
在 res -> drawable
下面将这一系列连续的图片加入进去。然后新建一个名为 fire_animation
的 xml
文件,在文件中给每个 item
添加图片资源和显示时长,如下:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/campfire01" android:duration="80"/>
<item android:drawable="@drawable/campfire02" android:duration="80"/>
<item android:drawable="@drawable/campfire03" android:duration="80"/>
<item android:drawable="@drawable/campfire04" android:duration="80"/>
<item android:drawable="@drawable/campfire05" android:duration="80"/>
<item android:drawable="@drawable/campfire06" android:duration="80"/>
<item android:drawable="@drawable/campfire07" android:duration="80"/>
<item android:drawable="@drawable/campfire08" android:duration="80"/>
<item android:drawable="@drawable/campfire09" android:duration="80"/>
<item android:drawable="@drawable/campfire10" android:duration="80"/>
<item android:drawable="@drawable/campfire11" android:duration="80"/>
<item android:drawable="@drawable/campfire12" android:duration="80"/>
<item android:drawable="@drawable/campfire13" android:duration="80"/>
<item android:drawable="@drawable/campfire14" android:duration="80"/>
<item android:drawable="@drawable/campfire15" android:duration="80"/>
<item android:drawable="@drawable/campfire16" android:duration="80"/>
<item android:drawable="@drawable/campfire17" android:duration="80"/>
</animation-list>
注意: 根节点如果是 set
的话,是不能循环动画的,只能播放一次就结束
2.activity中使用
接下来在 acctivity_main
中使用这个资源文件 fire_animation.xml
。最后在代码中解析成 AnimationDrawable
,使用就可以了。
v = findViewById(R.id.imageView)
animation = v.drawable as AnimationDrawable
animation.start()
效果如下:
当然,这也可以完全通过代码创建,
v = findViewById(R.id.imageView)
fun fireAnimation() {
val firesArray = arrayOf(
R.drawable.campfire01,
R.drawable.campfire02,
R.drawable.campfire03,
R.drawable.campfire04,
R.drawable.campfire05,
R.drawable.campfire06,
R.drawable.campfire07,
R.drawable.campfire08,
R.drawable.campfire09,
R.drawable.campfire10,
R.drawable.campfire11,
R.drawable.campfire12,
R.drawable.campfire13,
R.drawable.campfire14,
R.drawable.campfire15,
R.drawable.campfire16,
R.drawable.campfire17
)
AnimationDrawable().apply {
//添加图片资源
for (item in firesArray) {
addFrame(getDrawable(item)!!,80)
}
//关联图片和帧动画
v.setImageDrawable(this)
//启动
start()
}
}
二.矢量动画
矢量动画相较帧动画就稍显复杂,我们来讲讲使用矢量动画最简单的步骤吧。我们通过相关网站,进行动画设计,它会为我们快速生成 xml
文件,你可以选择导入图片的格式: SVG
, Android Drawable
。
屏幕右边的方框中,很多值都对应着代码中的值,上手相对容易,具体使用请自行百度.
设计完矢量动画之后,我们点击 Export
选择 Animated Vector Drawable
,它会自动为我们生成 xml
文件,之后我们将其添加至 drawable
文件夹中。
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
android:name="vector"
android:width="447dp"
android:height="285dp"
android:viewportWidth="447"
android:viewportHeight="285">
<path
android:name="path"
android:pathData="M 0.307 165.05 L 154.691 285.204 L 446.691 0.358"
android:strokeColor="#00aa00"
android:strokeWidth="20"
android:strokeLineCap="round"
android:strokeLineJoin="round"/>
</vector>
</aapt:attr>
<target android:name="path">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="trimPathEnd"
android:duration="500"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
</aapt:attr>
</target>
</animated-vector>
我们可以看到这个矢量动画的 xml
是这样的。那么接下来就是在代码中将其转化为 AnimatedVectorDrawable
类型(注意在布局中要将srcCompat换成当前的资源),这个和帧动画的使用非常相似。
v = findViewById(R.id.imageView)
val anim = v.drawable as AnimatedVectorDrawable
anim.start()
矢量动画主要麻烦在动画资源文件的书写,但是我们可以通过这个网站来快速获得你预想动画的代码,这个使用起来也是蛮简单的。
三.补间动画
补间动画也是蛮特殊的,控件在做动画时,它的位置其实还是停留在原处,因此如果想在动画结束后给控件加点击事件,这样做是无效的,你需要通过我们待会要讲的属性动画来完成,但补间动画也有优点,就是制作简便,占用内存小等。
属性 | 解释 |
---|---|
duration |
动画时长,单位是毫秒 |
interpolator |
动画的播放模式,如匀速 |
repeatCount |
动画播放次数 |
repeatMode |
设置动画结束重新播放动画还是倒放动画 |
start() |
启动动画 |
cancel() |
取消动画 |
fillBefore |
动画播放结束是否保持动画开始状态 |
fillAfter |
动画播放结束是否保持动画结束状态 |
补间动画有4种,分别是:RotateAnimation
-旋转动画
, TranslateAnimation
-位移动画
, AlphaAnimation
-透明度动画
, ScaleAnimation
-缩放动画
,
由于这几种动画创建的方式都一样,唯独就是部分属性值不一样,因此在这里就以 ScaleAnimation
为例,下面演示一下如何完成动画操作。
一共有两种完成动画的方式,xml创建
和 纯代码创建
1.在xml中创建完成动画
找到 res
文件夹,在下面新建一个 Android Resource Directory
,Resource type
选择 anim
。然后我们在里面写入以下代码,根节点是什么,就是什么动画,当然你也可以选择 set
一次定义多个动画。
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1" 设置缩放起始时的x轴的倍数
android:fromYScale="1" 设置缩放起始时的y轴的倍数
android:toXScale="50" 设置缩放结束时的x轴的倍数
android:toYScale="50" 设置缩放起始时的y轴的倍数
android:pivotX="50%" 设置缩放时以x轴的某点为中心进行缩放
android:pivotY="50%" 设置缩放时以y轴的某点为中心进行缩放
这两个属性加起来就是以物体中心点向四周缩放
android:duration="700" 动画完成时间
android:fillAfter="false"/> 动画是否保持结束时最后一刻的状态
然后就是在代码中使用这段动画了,
//获取控件
private val bgView = findViewById<View>(R.id.view)
//加载动画资源
scaleAnimation = AnimationUtils.loadAnimation(this,R.anim.btn_scale_anim)
//启动动画,和其他动画不同,补间动画启动是通过 view.startAnimation
bgView.startAnimation(scaleAnimation)
效果如下:
2.完全通过代码创建实现动画
val imageView = findvViewById<ImageView>(R.id.iamgeView)
animation = ScaleAnimation(
0f,//起始缩放倍数x轴
1f,//结束缩放倍数x轴
0f,//起始缩放倍数y轴
1f,//结束缩放倍数x轴
Animation.RELATIVE_TO_SELF,
0.5f,//相对自身x轴0.5倍距离
Animation.RELATIVE_TO_SELF,
0.5f//相对自身y轴0.5倍距离
).apply {
interpolator = LinearInterpolator()
repeatMode = Animation.REVERSE
duration = 5000
repeatCount = Animation.INFINITE
}
imageView.startAnimation(animation)
当我开始执行动画时就是以下效果:
四.属性动画
属性动画前面也提到了,通常是要在动画结束后有点击事件时运用。它使用起来很方便。属性动画的一些属性名称以及对应的值和渐变动画很多都一样,只是属性动画的暂停是 animator.pause()
。
属性动画常用的有两种 ObjectAnimator
和 ValueAnimator
。ObjectAnimator
是直观的给 Object
加上动画效果,能直观地为我们展示动画,如 translationX
就是在x轴上移动,而 ValueAnimator
是能产生很多关于动画的值,我们将这些值赋给每个动画因子,就可以完成很多花里胡哨的动画,如,我手动绘制一个这样的加载动画(屏幕上方那一个),它的一个动画因子就是 startAngle(画圆弧的起始角度)
。
下面就举例讲一个属性动画 translationX
。顾名思义,是在物体 x轴
方向上移动,向右移动是正,向左移动是负。
val v = findViewById<View>(R.id.view)
ObjectAnimator.ofFloat(v,"translationX",0f, height - 50f.apply {
duration = 350
interpolator = BounceInterpolator()
}.start()
由于是 ofFloat
所以参数都必须是 Float
类型!
- 当有多个动画时可以使用
AnimatorSet
设置同时播放或顺序播放。
//同时播放
AnimatorSet().playTogether(动画一,动画二)
//顺序播放,写在前面的先播放
AnimatorSet().playSequentially(动画一,动画二)
- 属性动画允许添加事件监听
val v = findViewById<View>(R.id.view)
ObjectAnimator.ofFloat(v, "translationX", - 2f, 0f).apply {
duration = 500
interpolator = LinearInterpolator()
addListener(
onStart = {
//动画开始时 TODO
},
onCancel = {
//动画取消时 TODO
},
onEnd = {
//动画结束时 TODO
},
onRepeat = {
//动画重复时 TODO
})
}.start()