Android動畫系列---轉(zhuǎn)場動畫詳解

前言

本文是Android動畫系列的最后一篇--轉(zhuǎn)場動畫,轉(zhuǎn)場動畫在大部分APP中都或多或少的有用到,例如兩個Activity之間的過渡動畫、Fragment切換時的過渡動畫等都屬于轉(zhuǎn)場動畫的范疇。

最初的轉(zhuǎn)場動畫

overridePendingTransition(int enterAnim,int exitAnim)

用來處理Activity之間的轉(zhuǎn)場動畫,常在 startActivity 或者 finsh操作之后調(diào)用。

只支持平移、縮放、透明度、旋轉(zhuǎn)四種動畫效果。

示例從MainActivity跳轉(zhuǎn)到ImageActivity,聲明兩個動畫 anim_in.xmlanim_out.xml分別對應圖中的 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實現(xiàn)的過渡動畫相比較而言是有些限制的,動畫效果往往也不是那么的絲滑。

Material Design轉(zhuǎn)場動畫

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

支持三種進入和退出過渡動畫效果:

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

Materia轉(zhuǎn)場過渡或者共享元素過渡都需要開啟有兩種方式:

第一種是通過在應用theme中通過 android:windowActivityTransitions開啟

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

第二種是在使用過渡動畫的Activity中通過代碼開啟

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

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

步驟一 在MainActivity中聲明退出動畫效果

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

步驟二在ImageActivity中聲明進入動畫效果

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)場動畫,還支持兩個Activity之間共享元素的動畫設(shè)置。比如我們查看一個圖片,可以通過使用 changeImageTransform共享元素過渡來給圖片尺寸和縮放方面的變化添加動畫效果。除了 changeImageTransform之外呢,還有另外三種共享元素過渡方式

  • changeBounds - 為目標視圖布局邊界的變化添加動畫效果。
  • changeClipBounds - 為目標視圖裁剪邊界的變化添加動畫效果。
  • changeTransform - 為目標視圖縮放和旋轉(zhuǎn)方面的變化添加動畫效果。

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

MainActivity

binding.shareImage1.setOnClickListener {
    val intent = Intent(this, ImageActivity::class.java)
    //只有一個共享元素視圖
    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) 方法接收一個需要共享的視圖以及名稱,sharedElementNameImageActivity中的共享視圖設(shè)置的transitionName保持一致。

如果需要設(shè)置多個共享元素動畫,可以使用Pair

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

效果圖


common_share_anim.gif

Android Material Motion

導入和使用

Material Components for Android 庫版本 1.4.0-alpha01及以上

該庫有兩種實現(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

從對比上來看,兩者兼容的最低版本不同分別是Android 3.0和Android 5.0 ,但是AndroidX不支持Activities和Windows,對于需要實現(xiàn)Activity之間過渡效果的需求不太友好,相對而講Platform支持的更全面,而且現(xiàn)在市場上Android 5.0最為最低版本可以覆蓋大部分機型,Platform 就可以作為首選實現(xiàn)。

過渡模式

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

  • Container transform

  • Shared axis

  • Fade through

  • Fade

Container transform

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


container_tranform.gif

示例代碼

Fragment之間的跳轉(zhuǎn)

FragmentA展示一個兩列的Grid列表,每個Item中使用CardView布局,點擊列表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來保證transiotionName的唯一性。這個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來作為endView,使用android:transitionName屬性來進行設(shè)置。

Tips: android:transitionName是API 21才支持的,低于API 21請使用setTransitionName方法進行設(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兩個參數(shù)一個是startView,在本示例中是item中的CardView,另外一個參數(shù)是endView的transitionName,設(shè)置完成后切換到FragmentB。

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

FragmentA

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

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

FragmentB

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

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

FragmentB中進入過渡效果有兩種設(shè)置方式。

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

Shared axis

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


shared_axis.gif

示例代碼

Activity之間使用

ActivityA中設(shè)置退出動畫

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

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

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

ActivityB中設(shè)置進入動畫

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

最后在ActivityA中進行跳轉(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)

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

image1image2root的內(nèi)部子視圖,通過TransitionManager.beginDelayedTransition(root, sharedTransition)root進行監(jiān)控后,image1image2視圖可見度變化后會直接觸發(fā)動畫效果。

Fade Through

淡入模式用于相互之間沒有很強關(guān)系的UI元素之間的轉(zhuǎn)換。

fade_through.gif

Fade Through的使用方式和Shared axis是一樣的,可以通過MaterialFadeThrough來實現(xiàn)。

Fade

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


fade.gif

示例代碼

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

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

總結(jié)

轉(zhuǎn)場動畫可以賦給一個應用活力,增加流暢性和可交互性,讓用戶在使用應用中不那么生硬,這也是我們需要掌握的。在實際需求中可以根據(jù)場景來采用不同的轉(zhuǎn)場動畫實現(xiàn)策略。如果覺得文章對您有幫助,請幫忙點個贊(#.#)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容