Android轉(zhuǎn)場(chǎng)動(dòng)畫深入分析探究
早期的轉(zhuǎn)場(chǎng)
最初,兩個(gè)Activity之間的切換的過(guò)度動(dòng)畫,都是用overridePendingTransition。它只支持平移、縮放、透明度、旋轉(zhuǎn)四種動(dòng)畫效果。
比如我們寫個(gè)平移跳轉(zhuǎn)動(dòng)畫,實(shí)現(xiàn)是這樣的。首先,我們?cè)谫Y源文件anim下新建兩個(gè)動(dòng)畫資源文件 enter_anim.xml 和 quit_anim.xml,分別表示進(jìn)入和退出的動(dòng)畫。
enter_anim.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500"> <translate android:fromXDelta="100%p" android:toXDelta="0" /> </set>
quit_anim.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500"> <translate android:fromXDelta="0" android:toXDelta="-100%p" /> </set>
然后在界面跳轉(zhuǎn)的時(shí)候,調(diào)用overridePendingTransition就行啦
startActivity(Intent(this, TestActivity::class.java)) overridePendingTransition(R.anim.enter_anim, R.anim.quit_anim)
Material Design 轉(zhuǎn)場(chǎng)動(dòng)畫
Android 5.0之后使用,具有三種轉(zhuǎn)場(chǎng)動(dòng)畫效果:
- Explode:爆炸式,將視圖移入場(chǎng)景中心或從中移出
- Fade:淡入淡出式,通過(guò)更改透明度來(lái)添加和移出視圖
- Slide:滑動(dòng)式,從場(chǎng)景的一個(gè)邊緣移入或移出視圖
Materia轉(zhuǎn)場(chǎng)有兩種啟用方式,一種是在theme中設(shè)置 windowActivityTransitions
<style name="Theme.AndroidApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <item name="android:windowActivityTransitions">true</item> </style>
一種是通過(guò)代碼開啟
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
下面,通過(guò)一個(gè)簡(jiǎn)單的示例,來(lái)瞧瞧具體是怎么去使用的
在MainActivity中設(shè)置退出動(dòng)畫,然后通過(guò)點(diǎn)擊事件去進(jìn)行跳轉(zhuǎn)到TestActivity
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { window.apply { requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) exitTransition = Fade() //退出動(dòng)畫 } super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.go.setOnClickListener { materialGo() } } private fun materialGo() { val intent = Intent(this, TestActivity::class.java) startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle()) } }
在TestActivity中設(shè)置進(jìn)入動(dòng)畫,這樣淡入淡出式就完成了
class TestActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { window.run { requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) enterTransition = Fade() //進(jìn)入動(dòng)畫 } super.onCreate(savedInstanceState) val binding = ActivityTestBinding.inflate(layoutInflater) setContentView(binding.root) } }
共享元素
如下所示,共享元素的效果很有趣,看著就像是圖片從一個(gè)頁(yè)面放大到另一個(gè)頁(yè)面
共享元素過(guò)渡方式有四種
- changeBounds:為目標(biāo)視圖布局邊界的變化添加動(dòng)畫效果
- changeClipBounds:為目標(biāo)視圖裁剪邊界的變化添加動(dòng)畫效果
- changeTransform:為目標(biāo)視圖縮放和旋轉(zhuǎn)方面的變化添加動(dòng)畫效果
- changeImageTransform:為目標(biāo)圖片尺寸和縮放方面的變化添加動(dòng)畫效果
首先需要設(shè)置transitionName,告訴系統(tǒng),哪個(gè)View需要做動(dòng)畫,然后進(jìn)行Activity的跳轉(zhuǎn)
binding.image.setOnClickListener { binding.image.transitionName = "shared_elements" val options = ActivityOptions.makeSceneTransitionAnimation(this, binding.image, "shared_elements") val intent = Intent(this, TestActivity::class.java) startActivity(intent, options.toBundle()) }
在目標(biāo)Activity中給View設(shè)置transitionName,也可添加一系列的過(guò)渡效果
class TestActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { val transitionSet = TransitionSet().apply { addTransition(ChangeBounds()) addTransition(ChangeClipBounds()) addTransition(ChangeTransform()) addTransition(ChangeImageTransform()) } with(window) { requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) sharedElementEnterTransition = transitionSet sharedElementExitTransition = transitionSet } super.onCreate(savedInstanceState) val binding = ActivityTestBinding.inflate(layoutInflater) setContentView(binding.root) binding.picture.transitionName = "shared_elements" } }
如果要使用多個(gè)共享元素,可使用Pair,例如
val options = ActivityOptionsCompat.makeSceneTransitionAnimation( this, Pair(binding.imageView, "imageView"), Pair(binding.signature, "signature") )
Material Motion 動(dòng)畫
它提供了四種模式,可以根據(jù)需求靈活選用,分別是:
MaterialContainerTransform
用于包含容器的界面元素之間的過(guò)渡,通過(guò)將一個(gè)UI元素?zé)o縫轉(zhuǎn)換為另一個(gè)UI元素,在兩個(gè)不同的界面元素之間創(chuàng)造可視化的連接,跟之前共享元素動(dòng)畫最大的不同點(diǎn)在于它可以是一個(gè) ViewGroup,也可以是一個(gè) View。
下面,我們通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)感受一下效果,item是個(gè)LinearLayout,用于點(diǎn)擊跳轉(zhuǎn)。
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { //1.啟用轉(zhuǎn)場(chǎng)動(dòng)畫 window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback()) super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) initView() } private fun initView() { //2.設(shè)置transitionName binding.item.transitionName = "share" binding.item.setOnClickListener { //3.進(jìn)行頁(yè)面跳轉(zhuǎn) startActivity( Intent(this, TestActivity::class.java), ActivityOptions.makeSceneTransitionAnimation(this, it, "share").toBundle() ) } } }
在目標(biāo)Activity中,只顯示了幾行文本,整體用LinearLayout做容器,id為display。
這里為了更加清楚的看到動(dòng)畫的轉(zhuǎn)換過(guò)程,我將動(dòng)畫的執(zhí)行時(shí)間duration設(shè)置為2秒,實(shí)際開發(fā)中,不能搞這么久哦。
class TestActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { //1.啟用轉(zhuǎn)場(chǎng)動(dòng)畫 window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback()) super.onCreate(savedInstanceState) val binding = ActivityTestBinding.inflate(layoutInflater) setContentView(binding.root) //2.設(shè)置transitionName binding.display.transitionName = "share" //3.設(shè)置具體的動(dòng)畫 window.sharedElementEnterTransition = MaterialContainerTransform().apply { addTarget(binding.display) scrimColor = Color.TRANSPARENT setAllContainerColors(Color.WHITE) duration = 2000L } window.sharedElementExitTransition = MaterialContainerTransform().apply { addTarget(binding.display) scrimColor = Color.TRANSPARENT setAllContainerColors(Color.WHITE) duration = 2000L } } }
MaterialContainerTransform有兩個(gè)屬性需要注意下:
- scrimColor:用于控制在動(dòng)畫容器后面繪制的半透明陰影的顏色。默認(rèn)情況下,該元素會(huì)設(shè)為 32% 黑色。這里將其設(shè)為透明,這意味著不會(huì)繪制任何紗罩。
- setAllContainerColors:在兩個(gè)視圖之間添加動(dòng)畫時(shí),它會(huì)在畫布上繪制 3 個(gè)容器: 后臺(tái)容器 ,起始視圖的容器和結(jié)束視圖的容器。對(duì)于這 3 個(gè)容器,我們都可以為其填充顏色,并將其默認(rèn)設(shè)為透明。如果您的起始視圖或結(jié)束視圖本身沒(méi)有繪制背景,導(dǎo)致在動(dòng)畫播放期間其他元素顯示在其下層,那么設(shè)置這些背景填充顏色可能會(huì)很有用。我們可以使用 setAllContainerColors 來(lái)統(tǒng)一顏色,確保我們不會(huì)遇到任何視覺(jué)問(wèn)題。
Shared axis
用于具有空間或?qū)Ш疥P(guān)系的界面元素之間的過(guò)渡,讓元素在轉(zhuǎn)換時(shí)共用 x 軸、y 軸或 z 軸,用以強(qiáng)調(diào)元素間的關(guān)系。
在MainActivity中設(shè)置退出動(dòng)畫
//啟用轉(zhuǎn)場(chǎng)動(dòng)畫 window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) window.exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true).apply { //指定轉(zhuǎn)換視圖 addTarget(R.id.list) //轉(zhuǎn)換不包含導(dǎo)航和狀態(tài)欄 excludeTarget(android.R.id.statusBarBackground, true) excludeTarget(android.R.id.navigationBarBackground, true) }
進(jìn)行跳轉(zhuǎn)
startActivity( Intent(this, TestActivity::class.java), ActivityOptions.makeSceneTransitionAnimation(this).toBundle() )
在TestActivity中設(shè)置進(jìn)入動(dòng)畫
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) window.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true).apply { addTarget(R.id.display) excludeTarget(android.R.id.statusBarBackground, true) excludeTarget(android.R.id.navigationBarBackground, true) }
然后,我們來(lái)看一下轉(zhuǎn)場(chǎng)效果
Fade Through
用于彼此之間沒(méi)有密切關(guān)系的界面元素之間的過(guò)渡,使用依序淡出和淡入的效果,并會(huì)對(duì)轉(zhuǎn)入的元素進(jìn)行縮放,用法跟MaterialSharedAxis差不多。
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) window.enterTransition = MaterialFadeThrough().apply { addTarget(R.id.display) excludeTarget(android.R.id.statusBarBackground, true) excludeTarget(android.R.id.navigationBarBackground, true) }
Fade
用于進(jìn)入或退出屏幕畫面范圍的界面元素。似乎效果上Fade 和上面的 Fade Through 差不多,其實(shí)確實(shí)都是透明度+縮放動(dòng)畫,但是官方建議,如果發(fā)生在同一個(gè)界面,例如在屏幕中心淡出的對(duì)話框。
這里為了更清楚的看清轉(zhuǎn)場(chǎng)過(guò)程,將動(dòng)畫的執(zhí)行時(shí)間duration設(shè)置為1000,實(shí)際開發(fā)中應(yīng)設(shè)置小點(diǎn),或者不用去設(shè)置
val materialFade = MaterialFade().apply { duration = 1000L } TransitionManager.beginDelayedTransition(binding.list, materialFade) binding.detail.visibility = View.VISIBLE
總結(jié)
在Android 轉(zhuǎn)場(chǎng)動(dòng)畫的發(fā)展中,早期的轉(zhuǎn)場(chǎng)支持平移、縮放、透明度、旋轉(zhuǎn)四種基礎(chǔ)動(dòng)畫效果,隨后,出現(xiàn)了Material Design 轉(zhuǎn)場(chǎng)動(dòng)畫,給我們帶來(lái)了共享元素動(dòng)畫效果,最后Material Motion 動(dòng)畫封裝了四種動(dòng)畫,使得轉(zhuǎn)場(chǎng)效果的實(shí)現(xiàn)更加容易。我覺(jué)得,頁(yè)面之間的轉(zhuǎn)場(chǎng)效果,可以賦予應(yīng)用活力,豐富用戶的使用體驗(yàn),升華應(yīng)用交互的靈魂,常言道,好看的皮囊千篇一律,有趣的靈魂萬(wàn)里挑一。
到此這篇關(guān)于Android轉(zhuǎn)場(chǎng)動(dòng)畫深入分析探究的文章就介紹到這了,更多相關(guān)Android轉(zhuǎn)場(chǎng)動(dòng)畫內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android?Flutter實(shí)現(xiàn)頁(yè)面切換轉(zhuǎn)場(chǎng)動(dòng)畫效果
- Android實(shí)現(xiàn)Reveal圓形Activity轉(zhuǎn)場(chǎng)動(dòng)畫的完整步驟
- Android工具欄頂出轉(zhuǎn)場(chǎng)動(dòng)畫的實(shí)現(xiàn)方法實(shí)例
- Android5.0之Activity的轉(zhuǎn)場(chǎng)動(dòng)畫的示例
- 詳解Android(共享元素)轉(zhuǎn)場(chǎng)動(dòng)畫開發(fā)實(shí)踐
- Android中轉(zhuǎn)場(chǎng)動(dòng)畫的實(shí)現(xiàn)與兼容性處理
- Android轉(zhuǎn)場(chǎng)效果實(shí)現(xiàn)示例淺析
相關(guān)文章
Android 布局控件之LinearLayout詳細(xì)介紹
Android 布局控件之LinearLayout詳細(xì)介紹,需要的朋友可以參考一下2013-05-05Android如何優(yōu)雅的處理重復(fù)點(diǎn)擊
這篇文章主要介紹了Android如何優(yōu)雅的處理重復(fù)點(diǎn)擊,幫助大家更好的理解和學(xué)習(xí)使用Android開發(fā),感興趣的朋友可以了解下2021-03-03Android屏幕適配工具類 Android自動(dòng)生成不同分辨率的值
這篇文章主要為大家詳細(xì)介紹了Android屏幕適配工具類,Android自動(dòng)生成不同分辨率的值,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03Android搭建grpc環(huán)境過(guò)程分步詳解
本篇文章使用的IDE是Android Studio。這里先吐槽一句,安卓項(xiàng)目搭建grpc環(huán)境,不管是引入插件還是引入第三方庫(kù),對(duì)于版本的要求都極為苛刻,一旦版本不匹配就會(huì)報(bào)錯(cuò),所以對(duì)于版本的搭配一定要注意2023-04-04Android 讀取文件內(nèi)容實(shí)現(xiàn)方法總結(jié)
這篇文章主要介紹了Android 讀取文件內(nèi)容實(shí)現(xiàn)方法的相關(guān)資料,這里提供了幾種方法,大家可以選擇使用,需要的朋友可以參考下2016-10-10Android 開發(fā) 使用WebUploader解決安卓微信瀏覽器上傳圖片中遇到的bug
這篇文章主要介紹了Android 開發(fā) 使用WebUploader解決安卓微信瀏覽器上傳圖片中遇到的bug問(wèn)題,本文給介紹的非常詳細(xì),需要的朋友可以參考下2016-11-11