Material Motion
Material Design 在1.2 推出了新的動畫Material Motion。提供了4種動畫的方式:
- Container transform
- Shared axis
- Fade Through
- Fade
目前1.2還在beta階段,我們就先來看一下這4種動畫有哪些實用地方。
Container transform
介紹Container transform 之前,我們先回顧一下 Activity Transition的動畫方式。makeSceneTransitionAnimation的動畫方式,第1頁與第2頁因為有圖片、文字內容一樣,透過視覺連續性達到動畫的效果。
而Container transform 則提供了另一種透過容器之間的變化而產生的一種動畫。因為重點在於容器而不是元件的本身內容,所以2頁之間並不需要有元件是長的很像或一樣才能使用動畫。我們把重點放在容器的變化,也就是外框形狀的改變。
🔹線上課程學習更快速有效「Android 動畫入門到進階」
以這個例子,點了搜尋Bar之後,開啟第2頁的方式會是由上往下延伸出現。
兩個頁面由畫面上來看,本身並沒有太大的關聯,但卻可以使用動畫的方式來開啟,這是因為我們只關注容器的改變。請看下圖,指的就是從左邊的紅框變為右邊紅框
首先在build.gradle加入dependencies
implementation 'com.google.android.material:material:1.2.0-alpha06'
第1頁的 activity.xml
在Toolbar加上transitonName
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:transitionName="shared_element_container">
</androidx.appcompat.widget.Toolbar>
第1頁的Activity
在onCreate設定離開這個Activity的動畫
override fun onCreate(savedInstanceState: Bundle?) { window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
setExitSharedElementCallback(
MaterialContainerTransformSharedElementCallback()
)
window.sharedElementsUseOverlay = true super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sample2) setSupportActionBar(toolbar)
}
點下Toolbar 開啟下一頁
使用 ActivityOptions.makeSceneTransitionAnimation 做為開啟Activity的動畫。
第1個參數的this
為該activity。
第2個參數searchFrameLayout
為該頁的Container,也就是id為searchFrameLayout的Toolbar。
第3個參數"shared_element_container",
為第2頁Activity的Transition name。
toolbar.setOnClickListener {
val intent = Intent(this, Sample2BActivity::class.java)
val options = ActivityOptions.makeSceneTransitionAnimation(
this, searchFrameLayout,
"shared_element_container"
)
startActivity(intent, options.toBundle())
}
第2頁Activity
- 設定RootView的TransitionName,這裡的android.R.id.content指的就是Root view。
2. 設定進入的Transition
3. 設定離開的Transition
override fun onCreate(savedInstanceState: Bundle?) {
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) //1. 設定RootView的TransitionName
findViewById<View>(android.R.id.content).transitionName
= "shared_element_container" setEnterSharedElementCallback(
MaterialContainerTransformSharedElementCallback()
) //2. 設定進入的Transition
window.sharedElementEnterTransition =
MaterialContainerTransform().apply {
duration = 3000
addTarget(android.R.id.content)
} //3. 設定離開的Transition
window.sharedElementReturnTransition =
MaterialContainerTransform().apply {
duration = 3000
addTarget(android.R.id.content)
}
}
這樣就完成這個動畫了。
再來看另一個範例,點擊RecyclerView的其中一個Item開啟第3頁。
設定Container
第1頁的Container:RecyclerView的被點擊的Item
第2頁的Container:第2頁整頁
第1頁Activity
- 在Item被點擊時,設定TransitionName
- 建立Activity Transition
- 開啟第2頁Activity
override fun onViewHolderClick(view: View) {
// 1.在Item被點擊時,設定TransitionName
view.transitionName = "shared_element_container"
val intent = Intent(this, Sample2CActivity::class.java) // 2. 建立Activity Transition
val options = ActivityOptions.makeSceneTransitionAnimation(
this,
view,
"shared_element_container"
) // 3. 開啟第2頁Activity
startActivity(intent, options.toBundle())
}
第2頁Activity
- 設定RootView的TransitionName,這裡的android.R.id.content指的就是Root view。
2. 設定進入的Transition
3. 設定離開的Transition
override fun onCreate(savedInstanceState: Bundle?) {
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) //1. 設定RootView的TransitionName,這裡的android.R.id.content指的就是Root view。
findViewById<View>(android.R.id.content).transitionName = "shared_element_container"
setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback()) //2. 設定進入的Transition
window.sharedElementEnterTransition = MaterialContainerTransform().apply {
duration = 3000
addTarget(android.R.id.content)
} //3. 設定離開的Transition
window.sharedElementReturnTransition = MaterialContainerTransform().apply {
duration = 3000
addTarget(android.R.id.content)
}
}
View
Container transform 也能在單一Activity或Fragment中實現這個動畫。
當一個UI隱藏,另一個UI出現時,就很適合用這個動畫。看起來就很像Fab消失了變成了上方的Title View。因為是在同一個Activity,我們就不需要用設定Transition name的方式。而是直接告訴Transform起始與結束的Container是哪個View就可以了。
在Fab被點擊時
- 設定startView 為
fab
- 設定endView 為
topView
(上方彈出的區塊) - 設定動畫。第1個參數為
container
,也就是你的動畫範圍,在這裡指的是Layout最外層的View。 - 設定
fab
隱藏、topView
顯示。
fab.setOnClickListener {
val transform = MaterialContainerTransform().apply {
// 1. 設定startView 為fab
startView = fab // 2. 設定endView 為topView (上方彈出的區塊)
endView = topView pathMotion = MaterialArcMotion()
scrimColor = Color.TRANSPARENT
duration = 3000
}
// 3. 設定動畫
TransitionManager.beginDelayedTransition(container, transform)
// 4. 設定Fab隱藏、topView顯示。
fab.visibility = View.GONE
topView.visibility = View.VISIBLE
}
Fragment
在不同Fragment 切換頁面時,也能透過設定Container達到動畫效果。
Container 設定
第1頁Fragment
- 點下圖片後,設定該圖片的TransitionName。
- 建立Fragment
- 設定動畫
- 開啟Fragment,設定ShareElement,其中的addSharedElement第1個參數是被點擊的該圖片,第2個參數是第2頁Fragment的Transition Name。
private fun startFragment(imageView: View, type: String) {
// 步驟1:點下圖片後,設定該圖片的TransitionName。
imageView.transitionName = "shared_element_container" // 步驟2:建立Fragment
val fragment = Sample1BFragment.newInstance(type) // 步驟3:設定動畫
val materialContainerTransform = MaterialContainerTransform() fragment.sharedElementEnterTransition = materialContainerTransform // 步驟4:開啟Fragment,設定ShareElement
activity!!.supportFragmentManager
.beginTransaction()
.addSharedElement(view, "shared_element_container")
.replace(R.id.container, fragment)
.addToBackStack(null)
.commit()
}
第2頁 Fragment 的Layout
在最外層的Layout設定android:transitionName="shared_element_container"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:transitionName="shared_element_container"
>
</LinearLayout>
第2頁 Fragment
onViewCreated設定進入的動畫就完成了。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
//設定進入的動畫
sharedElementEnterTransition = MaterialContainerTransform()
}
Material Motion 的Container transform 我們就介紹到這邊,你可以用在Activity、Fragment、View切換時使用這個動畫。後續我們將再接著介紹另外幾種Material Motion。
如果你對動畫有興趣,歡迎來我的「Android 動畫入門到進階」線上課程,裡面有更多的動畫教學。
下一篇將會介紹Shared Axis 的動畫方式