前面花了3篇的篇輻來講VectorDrawable 及 VectorDrawable animation。
我們就來做一個從Play變Pause的動畫,用慢動作來看如下圖:
1.為了讓從暫停到撥放有旋轉90度的效果,所以我們將撥放的Icon做成朝上的三角形
2.為了讓2個Icon可以變成動畫,我們知道pathData要是成對的,所以我們把三角形分為2半來處理,三角形的左右兩半會對映到Pause的左右兩塊
PathData
Play:M12,16 H5 L8.5,10.5 L12,5 M12,16 H19 L15.5,10.5 L12,5
pause:M10,18 H6 L6,6 L10,6 M14,18 H18 L18,6 L14,6
先來看一下我們在drawable放了哪些檔案
icon_Play.xml
因為我們在pathData裡畫的是朝上的三角形,這裡加上rotation=90,讓三角形變成play的樣子。
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="120dp"
android:height="120dp"
android:viewportHeight="24"
android:viewportWidth="24">
<group
android:name="iconGroup"
android:pivotX="12"
android:pivotY="12"
android:rotation="90">
<path
android:name="iconPath"
android:fillColor="#FF000000"
android:pathData="@string/play_path" />
</group>
</vector>
icon_pause.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="120dp"
android:height="120dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<group
android:name="iconGroup"
android:pivotX="12"
android:pivotY="12"
>
<path
android:name="iconPath"
android:fillColor="#FF000000"
android:pathData="@string/pause_path" />
</group>
</vector>
從play到pause的動畫
第1個objectAnimator:旋轉從90度轉到180度
為什麼從90度開始呢,因為一開始我們就將icon_paly旋轉90為play的三角形了。從90旋轉至180會讓play從朝上的三角形變成朝右的,會讓pause轉180度還是一樣。
第二個objectAnimator
pathData的轉換,由play轉為pause
adv_play_to_pause.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
xmlns:tools="http://schemas.android.com/tools"
android:drawable="@drawable/ic_pause"
tools:targetApi="lollipop">
<target android:name="iconGroup">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:duration="4000"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="90"
android:valueTo="180" />
</set>
</aapt:attr>
</target>
<target android:name="iconPath">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="4000"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="pathData"
android:valueFrom="@string/play_path"
android:valueTo="@string/pause_path"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>
從pause到play的動畫
第1個objectAnimator
旋轉從0轉到90度
第二個objectAnimator
pathData的轉換,由pause轉為play
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_play"
>
<target android:name="iconGroup">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:duration="4000"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="90" />
</set>
</aapt:attr>
</target>
<target android:name="iconPath">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="4000"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="pathData"
android:valueFrom="@string/pause_path"
android:valueTo="@string/play_path"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>
這邊可以發現,我們play的pathData與pause的pathData放在strings.xml,因為在icon、animation都會用到。
<resources>
<string name="pause_path">M10,18 H6 L6,6 L10,6 M14,18 H18 L18,6 L14,6</string>
<string name="play_path">M12,16 H5 L8.5,10.5 L12,5 M12,16 H19 L15.5,10.5 L12,5</string>
</resources>
最後,animated-selector裡就是play與pause的icon與transition了。
as_playpause.xml
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<item
android:id="@+id/pause"
android:drawable="@drawable/ic_pause"
app:state_pause="true" />
<item
android:id="@+id/play"
android:drawable="@drawable/ic_play" />
<transition
android:drawable="@drawable/avd_pause_to_play"
android:fromId="@id/pause"
android:reversible="false"
android:toId="@id/play" />
<transition
android:drawable="@drawable/avd_play_to_pause"
android:fromId="@id/play"
android:reversible="false"
android:toId="@id/pause" />
</animated-selector>
activity_main.xml,加上ImageView
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<ImageView
android:id="@+id/play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/as_playpause" />
</LinearLayout>
在MainActivity切換state
class MainActivity : AppCompatActivity() {
private val STATE_PLAY = intArrayOf(R.attr.state_play, -R.attr.state_pause)
private val STATE_PAUSE = intArrayOf(-R.attr.state_play, R.attr.state_pause)
var isPlay = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
play.setImageState(STATE_PLAY, true)
play.setOnClickListener {
if (isPlay) {
play.setImageState(STATE_PAUSE, true)
} else {
play.setImageState(STATE_PLAY, true)
}
isPlay = !isPlay
}
}
}
完整程式:
https://github.com/evanchen76/PlayPauseAnimation
線上課程:
Android 動畫入門到進階
Android UI 進階實戰(Material Design Component)
出版書:
Android TDD 測試驅動開發:從 UnitTest、TDD 到 DevOps 實踐