前言
動(dòng)畫是生活中必不可少的東西,只要在向用戶傳遞信息或展示內(nèi)容都會(huì)用到動(dòng)畫,接下來我們講講在 Android 中的一些動(dòng)畫,這些動(dòng)畫主要分為 4 種,分別是 幀動(dòng)畫, 矢量動(dòng)畫, 補(bǔ)間動(dòng)畫, 屬性動(dòng)畫。
一.幀動(dòng)畫
幀動(dòng)畫,顧名思義就是通過一張張圖片通過快速切換而到達(dá)的一種視覺效果,看起來像圖片中的物體動(dòng)起來一般,我們平常說的 60幀,120幀,指的就是一秒鐘播放 60張圖片或 120 張圖片。
1.在xml文件中添加圖片
在 res -> drawable 下面將這一系列連續(xù)的圖片加入進(jìn)去。然后新建一個(gè)名為 fire_animation 的 xml 文件,在文件中給每個(gè) item 添加圖片資源和顯示時(shí)長(zhǎng),如下:
<?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>
注意: 根節(jié)點(diǎn)如果是 set 的話,是不能循環(huán)動(dòng)畫的,只能播放一次就結(jié)束
2.activity中使用
接下來在 acctivity_main 中使用這個(gè)資源文件 fire_animation.xml。最后在代碼中解析成 AnimationDrawable,使用就可以了。
v = findViewById(R.id.imageView)
animation = v.drawable as AnimationDrawable
animation.start()
效果如下:

當(dāng)然,這也可以完全通過代碼創(chuàng)建,
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)
}
//關(guān)聯(lián)圖片和幀動(dòng)畫
v.setImageDrawable(this)
//啟動(dòng)
start()
}
}
二.矢量動(dòng)畫
矢量動(dòng)畫相較幀動(dòng)畫就稍顯復(fù)雜,我們來講講使用矢量動(dòng)畫最簡(jiǎn)單的步驟吧。我們通過相關(guān)網(wǎng)站,進(jìn)行動(dòng)畫設(shè)計(jì),它會(huì)為我們快速生成 xml 文件,你可以選擇導(dǎo)入圖片的格式: SVG, Android Drawable。

屏幕右邊的方框中,很多值都對(duì)應(yīng)著代碼中的值,上手相對(duì)容易,具體使用請(qǐng)自行百度.
設(shè)計(jì)完矢量動(dòng)畫之后,我們點(diǎn)擊 Export 選擇 Animated Vector Drawable,它會(huì)自動(dòng)為我們生成 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>
我們可以看到這個(gè)矢量動(dòng)畫的 xml 是這樣的。那么接下來就是在代碼中將其轉(zhuǎn)化為 AnimatedVectorDrawable 類型(注意在布局中要將srcCompat換成當(dāng)前的資源),這個(gè)和幀動(dòng)畫的使用非常相似。
v = findViewById(R.id.imageView)
val anim = v.drawable as AnimatedVectorDrawable
anim.start()
矢量動(dòng)畫主要麻煩在動(dòng)畫資源文件的書寫,但是我們可以通過這個(gè)網(wǎng)站來快速獲得你預(yù)想動(dòng)畫的代碼,這個(gè)使用起來也是蠻簡(jiǎn)單的。

三.補(bǔ)間動(dòng)畫
補(bǔ)間動(dòng)畫也是蠻特殊的,控件在做動(dòng)畫時(shí),它的位置其實(shí)還是停留在原處,因此如果想在動(dòng)畫結(jié)束后給控件加點(diǎn)擊事件,這樣做是無效的,你需要通過我們待會(huì)要講的屬性動(dòng)畫來完成,但補(bǔ)間動(dòng)畫也有優(yōu)點(diǎn),就是制作簡(jiǎn)便,占用內(nèi)存小等。
| 屬性 | 解釋 |
|---|---|
duration |
動(dòng)畫時(shí)長(zhǎng),單位是毫秒 |
interpolator |
動(dòng)畫的播放模式,如勻速 |
repeatCount |
動(dòng)畫播放次數(shù) |
repeatMode |
設(shè)置動(dòng)畫結(jié)束重新播放動(dòng)畫還是倒放動(dòng)畫 |
start() |
啟動(dòng)動(dòng)畫 |
cancel() |
取消動(dòng)畫 |
fillBefore |
動(dòng)畫播放結(jié)束是否保持動(dòng)畫開始狀態(tài) |
fillAfter |
動(dòng)畫播放結(jié)束是否保持動(dòng)畫結(jié)束狀態(tài) |
補(bǔ)間動(dòng)畫有4種,分別是:RotateAnimation-旋轉(zhuǎn)動(dòng)畫, TranslateAnimation-位移動(dòng)畫, AlphaAnimation-透明度動(dòng)畫, ScaleAnimation-縮放動(dòng)畫,
由于這幾種動(dòng)畫創(chuàng)建的方式都一樣,唯獨(dú)就是部分屬性值不一樣,因此在這里就以 ScaleAnimation 為例,下面演示一下如何完成動(dòng)畫操作。
一共有兩種完成動(dòng)畫的方式,xml創(chuàng)建 和 純代碼創(chuàng)建
1.在xml中創(chuàng)建完成動(dòng)畫
找到 res 文件夾,在下面新建一個(gè) Android Resource Directory,Resource type 選擇 anim。然后我們?cè)诶锩鎸懭胍韵麓a,根節(jié)點(diǎn)是什么,就是什么動(dòng)畫,當(dāng)然你也可以選擇 set 一次定義多個(gè)動(dòng)畫。
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="1" 設(shè)置縮放起始時(shí)的x軸的倍數(shù)
android:fromYScale="1" 設(shè)置縮放起始時(shí)的y軸的倍數(shù)
android:toXScale="50" 設(shè)置縮放結(jié)束時(shí)的x軸的倍數(shù)
android:toYScale="50" 設(shè)置縮放起始時(shí)的y軸的倍數(shù)
android:pivotX="50%" 設(shè)置縮放時(shí)以x軸的某點(diǎn)為中心進(jìn)行縮放
android:pivotY="50%" 設(shè)置縮放時(shí)以y軸的某點(diǎn)為中心進(jìn)行縮放
這兩個(gè)屬性加起來就是以物體中心點(diǎn)向四周縮放
android:duration="700" 動(dòng)畫完成時(shí)間
android:fillAfter="false"/> 動(dòng)畫是否保持結(jié)束時(shí)最后一刻的狀態(tài)
然后就是在代碼中使用這段動(dòng)畫了,
//獲取控件
private val bgView = findViewById<View>(R.id.view)
//加載動(dòng)畫資源
scaleAnimation = AnimationUtils.loadAnimation(this,R.anim.btn_scale_anim)
//啟動(dòng)動(dòng)畫,和其他動(dòng)畫不同,補(bǔ)間動(dòng)畫啟動(dòng)是通過 view.startAnimation
bgView.startAnimation(scaleAnimation)
效果如下:

2.完全通過代碼創(chuàng)建實(shí)現(xiàn)動(dòng)畫
val imageView = findvViewById<ImageView>(R.id.iamgeView)
animation = ScaleAnimation(
0f,//起始縮放倍數(shù)x軸
1f,//結(jié)束縮放倍數(shù)x軸
0f,//起始縮放倍數(shù)y軸
1f,//結(jié)束縮放倍數(shù)x軸
Animation.RELATIVE_TO_SELF,
0.5f,//相對(duì)自身x軸0.5倍距離
Animation.RELATIVE_TO_SELF,
0.5f//相對(duì)自身y軸0.5倍距離
).apply {
interpolator = LinearInterpolator()
repeatMode = Animation.REVERSE
duration = 5000
repeatCount = Animation.INFINITE
}
imageView.startAnimation(animation)
當(dāng)我開始執(zhí)行動(dòng)畫時(shí)就是以下效果:

四.屬性動(dòng)畫
屬性動(dòng)畫前面也提到了,通常是要在動(dòng)畫結(jié)束后有點(diǎn)擊事件時(shí)運(yùn)用。它使用起來很方便。屬性動(dòng)畫的一些屬性名稱以及對(duì)應(yīng)的值和漸變動(dòng)畫很多都一樣,只是屬性動(dòng)畫的暫停是 animator.pause() 。

屬性動(dòng)畫常用的有兩種 ObjectAnimator 和 ValueAnimator 。ObjectAnimator 是直觀的給 Object 加上動(dòng)畫效果,能直觀地為我們展示動(dòng)畫,如 translationX 就是在x軸上移動(dòng),而 ValueAnimator 是能產(chǎn)生很多關(guān)于動(dòng)畫的值,我們將這些值賦給每個(gè)動(dòng)畫因子,就可以完成很多花里胡哨的動(dòng)畫,如,我手動(dòng)繪制一個(gè)這樣的加載動(dòng)畫(屏幕上方那一個(gè)),它的一個(gè)動(dòng)畫因子就是 startAngle(畫圓弧的起始角度) 。

下面就舉例講一個(gè)屬性動(dòng)畫 translationX。顧名思義,是在物體 x軸 方向上移動(dòng),向右移動(dòng)是正,向左移動(dòng)是負(fù)。
val v = findViewById<View>(R.id.view)
ObjectAnimator.ofFloat(v,"translationX",0f, height - 50f.apply {
duration = 350
interpolator = BounceInterpolator()
}.start()
由于是 ofFloat 所以參數(shù)都必須是 Float 類型!
- 當(dāng)有多個(gè)動(dòng)畫時(shí)可以使用
AnimatorSet設(shè)置同時(shí)播放或順序播放。
//同時(shí)播放
AnimatorSet().playTogether(動(dòng)畫一,動(dòng)畫二)
//順序播放,寫在前面的先播放
AnimatorSet().playSequentially(動(dòng)畫一,動(dòng)畫二)
- 屬性動(dòng)畫允許添加事件監(jiān)聽
val v = findViewById<View>(R.id.view)
ObjectAnimator.ofFloat(v, "translationX", - 2f, 0f).apply {
duration = 500
interpolator = LinearInterpolator()
addListener(
onStart = {
//動(dòng)畫開始時(shí) TODO
},
onCancel = {
//動(dòng)畫取消時(shí) TODO
},
onEnd = {
//動(dòng)畫結(jié)束時(shí) TODO
},
onRepeat = {
//動(dòng)畫重復(fù)時(shí) TODO
})
}.start()