Material Motion

Evan Chen
Evan Android Note
Published in
14 min readApr 19, 2020

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

  1. 設定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

  1. 在Item被點擊時,設定TransitionName
  2. 建立Activity Transition
  3. 開啟第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

  1. 設定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被點擊時

  1. 設定startView 為fab
  2. 設定endView 為topView (上方彈出的區塊)
  3. 設定動畫。第1個參數為container,也就是你的動畫範圍,在這裡指的是Layout最外層的View。
  4. 設定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

  1. 點下圖片後,設定該圖片的TransitionName。
  2. 建立Fragment
  3. 設定動畫
  4. 開啟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 的動畫方式

--

--