我們已經在 Android 平臺和 AndroidX 過渡系統實現了以上過渡效果,以便在 Activity、Fragment 和 View 之間切換時輕鬆使用。
Android 平臺FAB
https://material.io/components/buttons-floating-action-button
chip
https://material.io/components/chips
卡片
https://material.io/components/cards
導航上下文
https://material.io/design/navigation/navigation-transitions.html#hierarchical-transitions
android:transitionName="@{@string/email_card_transition_name(email.id)}"第二個是 EmailFragment 內部的全屏卡片組件,這個組件可以設置一個靜態的過渡名稱,因為在視圖層級中只有這一個視圖。注意,兩個共享元素不需要使用相同的過渡名稱。過渡名稱
https://developer.android.google.cn/reference/android/view/View#attr_android:transitionName數據綁定
https://developer.android.google.cn/topic/libraries/data-bindingEmailFragment
https://github.com/material-components/material-components-android-examples/blob/develop/Reply/app/src/main/java/com/materialstudies/reply/ui/email/EmailFragment.kt這兩個視圖會被我們的容器轉換使用。工作原理是: 它們都會被放在一個 drawable 內部,此 drawable 的邊界會被裁剪到 "容器" 中,而 "容器" 會將自己的形狀通過動畫從一個列表項轉換為詳情頁。在過渡過程中,通過傳入頁面在傳出屏幕上淡入,容器的內容 (列表項和詳情頁) 發生了交換。
現在我們已經標記了共享元素的視圖,接下來就可以創建目的地 Fragment 的 sharedElementEnterTransition,並將其設置給一個 MaterialContainerTransform 的實例。默認情況下,從詳情頁面返回時,這個 sharedElementEnterTransition 會自動反轉並播放。
sharedElementEnterTransition = MaterialContainerTransform().apply { drawingViewId = R.id.nav_host_fragment duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong() scrimColor = Color.TRANSPARENT setAllContainerColors(requireContext().themeColor(R.attr.colorSurface))}有關 MaterialContainerTransform 參數的詳細信息,請參閱動效文檔:https://github.com/material-components/material-components-android/blob/master/docs/theming/Motion.md#container-transform當一封郵件被點擊時,我們所有需要做的就是為 Fragment 事務提供開始視圖和結束視圖過渡名稱之間的映射。有了這些信息,郵箱詳情 Fragment 共享元素過渡就可以使用我們提供的 MaterialContinaerTransform 找到並在兩個視圖之間進行動畫切換。
override fun onEmailClicked(cardView: View, email: Email) { exitTransition = MaterialElevationScale(false).apply { duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong() } reenterTransition = MaterialElevationScale(true).apply { duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong() } val emailCardDetailTransitionName = getString(R.string.email_card_detail_transition_name) val extras = FragmentNavigatorExtras(cardView to emailCardDetailTransitionName) val directions = HomeFragmentDirections.actionHomeFragmentToEmailFragment(email.id) findNavController().navigate(directions, extras) }在上面的代碼片段中,我們也為傳出頁郵件列表 Fragment 設置了 exit 和 reenter 的過渡效果。Material 組件提供了兩個過渡輔助: Hold 和 MaterialElevationScale,以平滑地為將要被替換的 Fragment 設置動畫。除了褪色 (Fade),MaterialElevationScale 還會在郵件列表頁退出時,對其進行縮放,並在重新進入郵件列表時縮放回來。Hold 僅僅是簡單地保留郵件列表。如果沒有設置退出時的過渡,我們的郵件列表會被立刻刪除並從視圖中消失。Hold
https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/transition/Hold.javaMaterialElevationScale
如果我們在這個時候運行代碼,從詳情頁導航返回到郵件列表頁,則返回過渡不會執行。這是因為當過渡開始時,郵件列表的適配器還未被填充,過渡系統找不到與過渡名稱對應的兩個視圖。幸運的是,有兩個簡單方法可供我們使用: postponeEnterTransition 和 startPostponedEnterTransition。這兩個方法允許我們延遲過渡,直到我們知道我們的共享元素已經被布局,並且可以被過渡系統發現。在 Reply 應用中,我們可以使用以下代碼延遲過渡,直到我們確定 RecyclerView 適配器已被填充,列表項已和過渡名稱綁定:
https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/transition/MaterialElevationScale.javapostponeEnterTransition()view.doOnPreDraw { startPostponedEnterTransition() }
在您自己的應用中,您可能需要嘗試這兩種方法,以根據您填充 UI 的方式和時間,來找到合適的時間開始延遲過渡。如果您發現您的返回動畫沒有執行,可能是在共享元素就緒之前開始了過渡。
接下來進入我們的搜索頁面。
共享軸模式用於有空間和導航關係的 UI 元素之間的過渡。在 Reply 應用中,打開搜索頁面會將用戶帶到郵件列表頂部的新頁面。為了介紹這個三維模型,我們可以在郵件列表 (HomeFragment) 和搜索頁面 (SearchFragment) 之間使用共享 z 軸過渡。
HomeFragment
https://github.com/material-components/material-components-android-examples/blob/develop/Reply/app/src/main/java/com/materialstudies/reply/ui/home/HomeFragment.ktSearchFragment
https://github.com/material-components/material-components-android-examples/blob/develop/Reply/app/src/main/java/com/materialstudies/reply/ui/search/SearchFragment.kt共享軸過渡會在操作兩個目標的同時創建最終的、編排過的過渡效果。這意味著 "成對" 的過渡會一起運行去創建連續的定向的動畫。對 Fragment 來說,這成對的過渡包括:
FragmentA 的 exitTransition 和 FragmentB 的 enterTransitionFragmentA 的 reenterTransition 和 FragmentB 的 returnTransitionMaterialSharedAxis 是實現了共享軸模式的類,它接收 forward 屬性來控制方向性的概念。在每一個過渡配對中,forward 必須被設置為相同的值,以便正確地協調這對動畫。如需了解更多關於共享軸方向性的詳細信息,請查閱動效文檔:https://material.io/design/motion/the-motion-system.html
MaterialSharedAxis
https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/transition/MaterialSharedAxis.java在 Reply 應用中,這是我們為當前的 Fragment (HomeFragment) 建立退出和重入過渡的方法。
currentNavigationFragment?.apply { exitTransition = MaterialSharedAxis( MaterialSharedAxis.Z, true ).apply { duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong() } reenterTransition = MaterialSharedAxis( MaterialSharedAxis.Z, false ).apply { duration =resources.getInteger(R.integer.reply_motion_duration_large).toLong() }}HomeFragment
https://github.com/material-components/material-components-android-examples/blob/develop/Reply/app/src/main/java/com/materialstudies/reply/ui/home/HomeFragment.kt在我們目的 fragment (SearchFragment) 中,我們建立進入和返回的過渡。
enterTransition = MaterialSharedAxis( MaterialSharedAxis.Z, /* forward= */ true).apply { duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()}returnTransition = MaterialSharedAxis( MaterialSharedAxis.Z, /* forward= */ false).apply { duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()}SearchFragment
https://github.com/material-components/material-components-android-examples/blob/develop/Reply/app/src/main/java/com/materialstudies/reply/ui/search/SearchFragment.kt注意: 當前 Fragment 的退出過渡和搜索 Fragment 的進入過渡使用相同的 forward 值 - true,當前 Fragment 的重入過渡和搜索 Fragment 的返回過渡也是如此。
接下來,默認情況下,過渡會在場景根層次結構內的所有子視圖上運行,這意味著一個共享軸過渡會應用於郵件列表上的每一封郵件以及搜索頁面的每一個子視圖。如果您想要 "傳播" 或者 "錯開" 動畫,這是一個非常好的功能,但是由於我們需要對每個 Fragment 的根作為整體進行動畫處理,我們需要在郵件列表的 RecyclerView 和我們的搜索頁面的根 view group 設置 android:transitionGroup="true"。
錯開
https://material.io/archive/guidelines/motion/choreography.html#choreography-creation郵件列表的 RecyclerView
https://github.com/material-components/material-components-android-examples/blob/develop/Reply/app/src/main/res/layout/fragment_home.xml#L18搜索頁面的根 view group
https://github.com/material-components/material-components-android-examples/blob/develop/Reply/app/src/main/res/layout/fragment_search.xml#L17這樣,我們就在進出搜索頁面時有了一個漂亮的共享 z 軸過渡!共享軸是一個非常靈活的過渡,可以應用於許多不同的場景,從頁面過渡到智能回複選擇,再到進入或者垂直的步驟流程。您已經配置好了設置,還可以嘗試使用 MaterialSharedAxis 的 axis 參數來了解其他軸動畫是什麼樣子。
我們要介紹的最後一個模式是淡入淡出模式。淡入淡出可用於在沒有強關係的 UI 元素間過渡。當在兩個信箱之間過渡時,我們不希望用戶認為他們已經發送的郵件和他們的收件箱在導航上相關。由於每個信箱是一個頂級的目的地,淡入淡出是一個合適的選擇。在 Reply 應用中,我們將用不同的電子郵件列表 (帶有新參數的 HomeFragment) 替換電子郵件列表 (HomeFragment)。由於 MaterialFadeThrough 沒有方向性,所以設置起來更加簡單。我們只需要為傳出 Fragment 設置一個退出過渡,為傳入 Fragment 設置一個進入過渡。
currentNavigationFragment?.apply { exitTransition = MaterialFadeThrough().apply { duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong() }}enterTransition = MaterialFadeThrough().apply { duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()}在郵件列表的 RecyclerView 上設置 android:transitionGroup="true" 的需求同樣適用於這裡,但是我們已經在共享軸配置的步驟中解決了這個問題。郵件列表的 RecyclerView
https://github.com/material-components/material-components-android-examples/blob/develop/Reply/app/src/main/res/layout/fragment_home.xml#L25以上就是淡入淡出過渡!您可以在自己項目有趣的地方來使用淡入淡出模式,比如: 底部導航欄的切換、列表項的交換,或替換一個工具欄菜單。
本文簡要介紹了 Android 的 Material 動效系統。通過使用該系統所提供的模式,您可以在自定義動效時,做很多事情,使動效成為品牌體驗的一部分。本文我們看到了 Fragment 的過渡,但動效系統也可用於 Activity 甚至 View 間的過渡。查看完整的動效規範文檔,獲得更多啟發,以便思考哪些地方可提高您應用的核心體驗,或在一些小的地方增加額外的樂趣。Material 動效開發文檔: 您可以在 Material Android 動效文檔找到許多關於在 Activity 和 View 之間進行動畫的自定義選項和建議。
https://github.com/material-components/material-components-android/blob/master/docs/theming/Motion.md
Material 動效 Codelab: 一個完整的分步的開發者教程,內容涉及如何在 Reply 應用中添加 Material 動效。
https://codelabs.developers.google.com/codelabs/material-motion-android/#0
Android Google 雲盤: 您可以在 Android Google 雲盤應用中看到正在運行的動效系統。點擊文件夾、打開搜索、在底部導航間切換,這些都用到了 MDC-Android 的過渡效果。
https://play.google.com/store/apps/details?id=com.google.android.apps.docs點擊屏末 | 閱讀原文 | 即刻了解更多 Material 動效相關內容
👆點擊獲取 "開發者的日常" 表情包