Android動(dòng)畫(huà)系列---轉(zhuǎn)場(chǎng)動(dòng)畫(huà)詳解

前言

本文是Android動(dòng)畫(huà)系列的最后一篇--轉(zhuǎn)場(chǎng)動(dòng)畫(huà)黔牵,轉(zhuǎn)場(chǎng)動(dòng)畫(huà)在大部分APP中都或多或少的有用到黎休,例如兩個(gè)Activity之間的過(guò)渡動(dòng)畫(huà)、Fragment切換時(shí)的過(guò)渡動(dòng)畫(huà)等都屬于轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的范疇烦绳。

最初的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

overridePendingTransition(int enterAnim灌旧,int exitAnim)

用來(lái)處理Activity之間的轉(zhuǎn)場(chǎng)動(dòng)畫(huà),常在 startActivity 或者 finsh操作之后調(diào)用悴晰。

只支持平移、縮放逐工、透明度铡溪、旋轉(zhuǎn)四種動(dòng)畫(huà)效果。

示例從MainActivity跳轉(zhuǎn)到ImageActivity泪喊,聲明兩個(gè)動(dòng)畫(huà) anim_in.xmlanim_out.xml分別對(duì)應(yīng)圖中的 in 和 out部分

anim_in.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">
    <translate
        android:fromXDelta="100%p"
        android:toXDelta="0" />

    <alpha
        android:fromAlpha="0"
        android:toAlpha="1.0" />
</set>

anim_out.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">
    <translate
        android:fromXDelta="0"
        android:toXDelta="-100%p" />

    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0" />
</set>

MainActivitystartActivity之后調(diào)用overridePendingTransition方法

binding.btn.setOnClickListener {
    val intent = Intent(this, ImageActivity::class.java)
    startActivity(intent)
    overridePendingTransition(R.anim.anim_in, R.anim.anim_out)
}

overridePendingTransition實(shí)現(xiàn)的過(guò)渡動(dòng)畫(huà)相比較而言是有些限制的棕硫,動(dòng)畫(huà)效果往往也不是那么的絲滑。

Material Design轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

支持Android5.0 (API 21)以上使用

支持三種進(jìn)入和退出過(guò)渡動(dòng)畫(huà)效果:

  • 爆炸式(Explode) - 將視圖移入場(chǎng)景中心或從中移出
  • 滑動(dòng)式(Slide) - 將視圖從場(chǎng)景的其中一個(gè)邊緣移入或移出
  • 淡入淡出式(Fade) - 通過(guò)更改視圖的不透明度袒啼,在場(chǎng)景中添加視圖或從中移除視圖
如何啟用

Materia轉(zhuǎn)場(chǎng)過(guò)渡或者共享元素過(guò)渡都需要開(kāi)啟有兩種方式:

第一種是通過(guò)在應(yīng)用theme中通過(guò) android:windowActivityTransitions開(kāi)啟

<style name="Theme.MyTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <item name="android:windowActivityTransitions">true</item>
</style>

第二種是在使用過(guò)渡動(dòng)畫(huà)的Activity中通過(guò)代碼開(kāi)啟

with(window) {
    requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)
}
示例代碼

假設(shè)我們從MainActivity跳轉(zhuǎn)到ImageActivity 哈扮,使用Material的過(guò)渡動(dòng)畫(huà)可以分為三步

步驟一 在MainActivity中聲明退出動(dòng)畫(huà)效果

with(window) {
        requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)
        //使用淡入淡出效果
    exitTransition = Fade()
 }

步驟二在ImageActivity中聲明進(jìn)入動(dòng)畫(huà)效果

with(window) {
    requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)
    //使用淡入淡出效果
    enterTransition = Fade()
}

最后呢在MainActivity中執(zhí)行跳轉(zhuǎn)

val intent = Intent(this, FadeActivity::class.java)
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
共享元素

Material Design除了支持Activity之間的轉(zhuǎn)場(chǎng)動(dòng)畫(huà),還支持兩個(gè)Activity之間共享元素的動(dòng)畫(huà)設(shè)置蚓再。比如我們查看一個(gè)圖片滑肉,可以通過(guò)使用 changeImageTransform共享元素過(guò)渡來(lái)給圖片尺寸和縮放方面的變化添加動(dòng)畫(huà)效果。除了 changeImageTransform之外呢摘仅,還有另外三種共享元素過(guò)渡方式

  • changeBounds - 為目標(biāo)視圖布局邊界的變化添加動(dòng)畫(huà)效果靶庙。
  • changeClipBounds - 為目標(biāo)視圖裁剪邊界的變化添加動(dòng)畫(huà)效果。
  • changeTransform - 為目標(biāo)視圖縮放和旋轉(zhuǎn)方面的變化添加動(dòng)畫(huà)效果娃属。

共享元素過(guò)渡效果的實(shí)現(xiàn)需要兩個(gè)Activity之間的‘共享’視圖指定同一個(gè)名稱六荒,例如從MainActivity 中的 ImageView 到 ImageActivity 中的ImageView 可以這樣去設(shè)置:

MainActivity

binding.shareImage1.setOnClickListener {
    val intent = Intent(this, ImageActivity::class.java)
    //只有一個(gè)共享元素視圖
    val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
        this,
        binding.shareImage1,
        "shareImage"
    )
    startActivity(intent, options.toBundle())
}

ImageActivity

override fun onCreate(savedInstanceState: Bundle?) {
       ...
        ViewCompat.setTransitionName(binding.shareImage, "shareImage")

   }

MainActivity中的 ActivityOptionsCompat.makeSceneTransitionAnimation(Activity activity,View shareElement,String sharedElementName) 方法接收一個(gè)需要共享的視圖以及名稱护姆,sharedElementNameImageActivity中的共享視圖設(shè)置的transitionName保持一致。

如果需要設(shè)置多個(gè)共享元素動(dòng)畫(huà)掏击,可以使用Pair

val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
    this, Pair(binding.shareImage1, "shareImage"),
    Pair(binding.shareText, "shareText")
)

效果圖


common_share_anim.gif

Android Material Motion

導(dǎo)入和使用

Material Components for Android 庫(kù)版本 1.4.0-alpha01及以上

該庫(kù)有兩種實(shí)現(xiàn)卵皂,一種是基于AndroidX Transition Library ,另外一種是基于Android Transition Framework砚亭,兩者之前的區(qū)別如下

AndroidX

  • 在 com.google.android.material.transition 包下

  • 支持 API Level 14+

  • 支持 Fragments 和 Views灯变,不支持 Activities 和 Windows

Platform

  • 在 com.google.android.material.transition.platform 包下

  • 支持 API Level 21+

  • 支持 Fragments、 Views,钠惩、Activities 和 Windows

從對(duì)比上來(lái)看柒凉,兩者兼容的最低版本不同分別是Android 3.0和Android 5.0 ,但是AndroidX不支持Activities和Windows篓跛,對(duì)于需要實(shí)現(xiàn)Activity之間過(guò)渡效果的需求不太友好膝捞,相對(duì)而講Platform支持的更全面,而且現(xiàn)在市場(chǎng)上Android 5.0最為最低版本可以覆蓋大部分機(jī)型愧沟,Platform 就可以作為首選實(shí)現(xiàn)蔬咬。

過(guò)渡模式

Material Components for Android 庫(kù)提供了四種motion模式,可以根據(jù)需求靈活選擇實(shí)現(xiàn):

  • Container transform

  • Shared axis

  • Fade through

  • Fade

Container transform

容器轉(zhuǎn)換模式設(shè)計(jì)用于包含容器的UI元素之間的轉(zhuǎn)換沐寺。此模式在兩個(gè)UI元素之間創(chuàng)建可見(jiàn)連接林艘。不同于傳統(tǒng)的共享元素動(dòng)畫(huà),它并不圍繞 單一的共享內(nèi)容而設(shè)計(jì)的混坞,相反狐援,這里的共享元素可以是包含 View 或者 ViewGroup 的邊界容器。


container_tranform.gif

示例代碼

Fragment之間的跳轉(zhuǎn)

FragmentA展示一個(gè)兩列的Grid列表究孕,每個(gè)Item中使用CardView布局啥酱,點(diǎn)擊列表Item觸發(fā)跳轉(zhuǎn)到FragmentB。

item_recycler_list.xml

<androidx.cardview.widget.CardView
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

MyAdapter - onBindViewHolder(holder:Myholder,position:Int)

holder.cardView.transitionName = "shared_image$position"

設(shè)置cardview的transitionName厨诸,這里使用position來(lái)保證transiotionName的唯一性镶殷。這個(gè)CardView作為startView。

fragment_b.xml

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/white"
    android:transitionName="shared_image">

fragment布局中聲明endView微酬,這里使用LinearLayout來(lái)作為endView绘趋,使用android:transitionName屬性來(lái)進(jìn)行設(shè)置。

Tips: android:transitionName是API 21才支持的颗管,低于API 21請(qǐng)使用setTransitionName方法進(jìn)行設(shè)置陷遮。

FragmentA.kt

adapter.clickListener = { holder, _ ->
    (activity as ContainerTransformActivity).replace(holder.cardView, "shared_image")
}

ContainerTransformActivity.kt

fun replace(view: View, name: String) {
    val fragmentB = FragmentB()
    supportFragmentManager.beginTransaction()
        .addSharedElement(view, name)
        .replace(R.id.fragment_container, fragmentB, "fragmentB")
        .addToBackStack("fragmentB")
        .commit()
}

addSharedElement兩個(gè)參數(shù)一個(gè)是startView,在本示例中是item中的CardView垦江,另外一個(gè)參數(shù)是endView的transitionName拷呆,設(shè)置完成后切換到FragmentB。

最后一步需要設(shè)置過(guò)渡模式

FragmentA

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    exitTransition = MaterialElevationScale(false).apply {
        duration = 250
    }
    reenterTransition = MaterialElevationScale(true).apply {
        duration = 250
    }
}

FragmentA中的過(guò)渡效果可以在replace FragmentB之前任意位置設(shè)置。

FragmentB

//第一種
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    sharedElementEnterTransition = MaterialContainerTransform()
}

//第二種
val fragmentB = FragmentB()
fragmentB.sharedElementEnterTransition = MaterialContainerTransform()

FragmentB中進(jìn)入過(guò)渡效果有兩種設(shè)置方式茬斧。

設(shè)置完成后就可以看到效果了腰懂。

Shared axis

共享軸模式用于具有空間或?qū)Ш疥P(guān)系的UI元素之間的轉(zhuǎn)換。此模式使用x项秉、y或z軸上的共享轉(zhuǎn)換來(lái)加強(qiáng)元素之間的關(guān)系绣溜。


shared_axis.gif

示例代碼

Activity之間使用

ActivityA中設(shè)置退出動(dòng)畫(huà)

window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
val exit = MaterialSharedAxis(MaterialSharedAxis.Z, true)
window.exitTransition = exit

默認(rèn)是整個(gè)視圖參與轉(zhuǎn)換,包括狀態(tài)欄和導(dǎo)航欄娄蔼,如果需要排除的話怖喻,可以使用如下代碼設(shè)置:

val exit = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
    //1.指定轉(zhuǎn)換視圖 
    addTarget(R.id.root)
    
    //2.排除狀態(tài)欄和導(dǎo)航啦參與轉(zhuǎn)換
    excludeTarget(android.R.id.statusBarBackground, true)
    excludeTarget(android.R.id.navigationBarBackground, true)
}

ActivityB中設(shè)置進(jìn)入動(dòng)畫(huà)

window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
val enter = MaterialSharedAxis(MaterialSharedAxis.Z, true)
window.enterTransition = enter

最后在ActivityA中進(jìn)行跳轉(zhuǎn)

val intent = Intent(this, ActivityB::class.java)
val scene = ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
startActivity(intent, scene)

View之間使用

val sharedTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)

//該方法會(huì)將root視圖進(jìn)行監(jiān)控,root內(nèi)部視圖可見(jiàn)性變化之后觸發(fā)動(dòng)畫(huà)
android.transition.TransitionManager.beginDelayedTransition(root, sharedTransition)
image1.visibility = View.GONE
image2.visibility = View.VISIBLE

image1image2root的內(nèi)部子視圖岁诉,通過(guò)TransitionManager.beginDelayedTransition(root, sharedTransition)root進(jìn)行監(jiān)控后锚沸,image1image2視圖可見(jiàn)度變化后會(huì)直接觸發(fā)動(dòng)畫(huà)效果。

Fade Through

淡入模式用于相互之間沒(méi)有很強(qiáng)關(guān)系的UI元素之間的轉(zhuǎn)換涕癣。

fade_through.gif

Fade Through的使用方式和Shared axis是一樣的哗蜈,可以通過(guò)MaterialFadeThrough來(lái)實(shí)現(xiàn)。

Fade

淡出模式用于在屏幕范圍內(nèi)進(jìn)入或退出的UI元素坠韩,例如在屏幕中心淡出的對(duì)話框距潘。


fade.gif

示例代碼

showButton.setOnClickListener {
   val materialFade = MaterialFade().apply {
     duration = 150L
   }
   TransitionManager.beginDelayedTransition(container, materialFade)
   fab.visibility = View.VISIBLE
}

淡出模式可以用于Dialog、menu等控件的顯示只搁。

總結(jié)

轉(zhuǎn)場(chǎng)動(dòng)畫(huà)可以賦給一個(gè)應(yīng)用活力音比,增加流暢性和可交互性,讓用戶在使用應(yīng)用中不那么生硬氢惋,這也是我們需要掌握的洞翩。在實(shí)際需求中可以根據(jù)場(chǎng)景來(lái)采用不同的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)實(shí)現(xiàn)策略。如果覺(jué)得文章對(duì)您有幫助焰望,請(qǐng)幫忙點(diǎn)個(gè)贊(#.#)骚亿。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市柿估,隨后出現(xiàn)的幾起案子循未,更是在濱河造成了極大的恐慌陷猫,老刑警劉巖秫舌,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異绣檬,居然都是意外死亡足陨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)娇未,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)墨缘,“玉大人,你說(shuō)我怎么就攤上這事∧魉希” “怎么了宽涌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蝶棋。 經(jīng)常有香客問(wèn)我卸亮,道長(zhǎng),這世上最難降的妖魔是什么玩裙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任兼贸,我火速辦了婚禮,結(jié)果婚禮上吃溅,老公的妹妹穿的比我還像新娘溶诞。我一直安慰自己,他們只是感情好决侈,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布螺垢。 她就那樣靜靜地躺著,像睡著了一般颜及。 火紅的嫁衣襯著肌膚如雪甩苛。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天俏站,我揣著相機(jī)與錄音讯蒲,去河邊找鬼。 笑死肄扎,一個(gè)胖子當(dāng)著我的面吹牛墨林,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播犯祠,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼旭等,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了衡载?” 一聲冷哼從身側(cè)響起搔耕,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痰娱,沒(méi)想到半個(gè)月后弃榨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡梨睁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年鲸睛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坡贺。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡官辈,死狀恐怖箱舞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拳亿,我是刑警寧澤晴股,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站肺魁,受9級(jí)特大地震影響队魏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜万搔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一胡桨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瞬雹,春花似錦昧谊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至胖缤,卻和暖如春尚镰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哪廓。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工狗唉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涡真。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓分俯,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親哆料。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缸剪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容