Android 12上全新的應用啓動畫面,還不適配一下?

早期的Android上App的啓動速度常爲人詬病,現在的啓動表現已不遜iOS。Google針對系統的不斷優化絕對功不可沒,從8.0獨立出來的SplashWindow,到12上推出的全新SplashScreenjava

在App的主要內容展現以前,按照需求的不一樣,或多或少會先展現這樣幾個畫面。android

畫面 用途
Splash Screen 展現品牌Logo或Slogan
Advertisement Screen 展現節日活動或平常廣告
Guide Screen 演示重點功能,通常只展現一次

啓動過程示意圖

1 前言

咱們經常花費精力去打造引導畫面或廣告畫面,而做爲第一印象的啓動畫面卻容易被忽視。回想下之前都是怎麼處理這個畫面的:git

  1. 通常經過設置windowSplashscreenContent屬性來展現UI提供的啓動圖,系統將爲它建立專門的Windowgithub

  2. 假使忘記設置這個屬性的話,默認的白色背景將致使啓動過程當中會有個白畫面一閃而過markdown

  3. 要去掉這個突兀的白畫面可不能簡單地設置Background爲null,否則一閃而過的又會變成黑畫面app

  4. 最終發現windowDisablePreview屬性能夠完全關閉這個畫面,這樣一來確實沒有任何突兀的畫面一閃而過了async

但這又會帶來啓動"變慢"的反作用,由於用來過渡的啓動畫面被關閉以後,App描畫前屏幕幾乎沒有什麼變化。即使App性能沒有劣化,但爲了留住用戶,咱們仍是得好好對待這個啓動畫面。ide

然而現有的windowSplashscreenContent可供定製的空間着實有限。也許官方也注意到了這點,便精心設計了Splash Screen API,並在Android 12裏重磅推出。oop

有了這個全新特性的幫助,啓動畫面的定製將更加自由、方便。先來看下采用SplashScreen API 快速定製的啓動效果。性能

在這裏插入圖片描述

下面將逐步演示全新SplashScreen可供定製的各個方面。

2 定製進入效果

採用xml便可快速定製各式進入效果。

2.1 默認的啓動效果

默認狀況下啓動畫面將展現白色背景和Launcher上的Adaptive Icon,也是不錯的,比之前的白畫面要好不少。

在這裏插入圖片描述

2.2 自定義靜態Icon

替換Icon爲Adaptive Icon的前景圖,背景色微調爲米黃色。

<item name="android:windowSplashScreenBackground">@color/newSplashScreenColor</item>
<item name="android:windowSplashScreenAnimatableIcon">@drawable/ic_kotlin_hero_new</item>
複製代碼

在這裏插入圖片描述

2.3 自定義Icon背景

Icon色調和畫面背景色的對比不夠明顯的狀況下,能夠添加Icon背景色增強辨識度。

<item name=」android:windowSplashScreenIconBackground」>@color/newSplashIconMaskColor</item>
複製代碼

在這裏插入圖片描述

2.4 自定義品牌Logo

添加品牌Logo能夠展現企業形象或Slogan,使得啓動畫面更爲完整和精細。

<item name=」android:windowSplashScreenBrandingImage」>@drawable/ic_tm_brand_newer</item>
複製代碼

在這裏插入圖片描述

2.5 自定義動畫Icon

動畫形式的Icon能夠增添設計和創意,使得啓動流程更加流暢和有趣。

<item name="android:windowSplashScreenAnimatableIcon">@drawable/ic_kotlin_hero_new_animated_rotate</item>
<item name="android:windowSplashScreenAnimationDuration">@integer/icon_animator_duration</item>
複製代碼

好比讓機器人圖標旋轉起來。

在這裏插入圖片描述

再好比讓機器人在Kotlin上側滑。

在這裏插入圖片描述

或者讓幾何圖案拼湊出字母K以後和機器人匯合,象徵着AndroidKotlin的強強聯合。

在這裏插入圖片描述

注意:

  • 動畫Icon的時長上限爲1000ms
  • 圖標的進入動畫能夠定製,但由系統控制,不能夠被監聽和額外處理。

2.6 延長啓動畫面

The splash screen is dismissed as soon as your app draws its first frame. If you need to load a small amount of data such as in-app theme settings from a local disk asynchronously, you can use ViewTreeObserver.OnPreDrawListener to suspend the app to draw its first frame.

後臺數據的加載不免耗時,啓動畫面結束了主要內容仍未加載好的話,體驗不是太好。可以控制啓動畫面的持續時時長就行了。

現有的ViewTreeObserver的OnPreDrawListener回調是能夠掛起描畫的,若是咱們在數據準備好以後再放行描畫,就能夠間接地延長啓動畫面的顯示。

好比Activity初始化2s後才放行描畫。

class SplashActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        keepSplashScreenLonger()
    }

    private fun keepSplashScreenLonger() {
        // 監聽Content View的描畫時機
        val content: View = findViewById(android.R.id.content)
        content.viewTreeObserver.addOnPreDrawListener(
            object : ViewTreeObserver.OnPreDrawListener {
                override fun onPreDraw(): Boolean {
                    // 準備好了描畫放行,反之掛起
                    return if (viewModel.isDataReady()) {
                        content.viewTreeObserver.removeOnPreDrawListener(this)
                        true
                    } else {
                        false
                    }
                }
            }
        )
    }
}

class MyViewModel(application: Application): AndroidViewModel(application) {
    companion object {
        const val WORK_DURATION = 2000L
    }
    private val initTime = SystemClock.uptimeMillis()
    fun isDataReady() = SystemClock.uptimeMillis() - initTime > WORK_DURATION
}
複製代碼

看一下效果,發現啓動畫面的展現時間確實變長了。

在這裏插入圖片描述

3 定製退出效果

當App的第一幀開始描畫,SplashScreen將會退出展現。爲了豐富退出環節的體驗,系統也開放了相應的入口,即畫面退出的回調。在這個回調裏能夠開始退出效果的定製,包括總體的退出動畫和圖標的退出動畫。

3.1 監聽啓動畫面的退出

向SplashScreen註冊OnExitAnimationListener接口便可監聽啓動畫面的退出。

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    customizeSplashScreenExit()
}

private fun customizeSplashScreenExit() {
    splashScreen.setOnExitAnimationListener { splashScreenView ->
        Log.d("Splash", "SplashScreen#onSplashScreenExit view:$splashScreenView")
        sleep(1000)
        Log.d("Splash", "SplashScreen#remove after sleeping")
        splashScreenView.remove()
    }
}
複製代碼

能夠看到啓動畫面展現以後,不做定製的默認狀況下就是全屏一下再消失。

在這裏插入圖片描述

日誌以下:

Splash  : Activity:com.example.splash.MainActivity@f70c0d0 Activity:com.example.splash.MainActivity@f70c0d0 onCreate
Splash  : Activity:com.example.splash.MainActivity@f70c0d0 onStart
Splash  : Activity:com.example.splash.MainActivity@f70c0d0 onResume
Splash  : SplashScreen#onSplashScreenExit view:android.window.SplashScreenView{18339d5 V.E...... ........ 0,0-1080,2280}
Splash  : SplashScreen#remove after sleeping
複製代碼

必定記得調用remove及時移除啓動畫面,不然SplashScreen會長時間蓋在主畫面上,大概在5s左右。

另外,回調的註冊須要放在Activity#onResume前,否則監聽不到。

3.2 定製總體的退出動畫

能夠給啓動畫面的總體設置TRANSLATESCALEROTATEALPHA等各類動畫,使得退出更加天然。

好比給SplashScreen加上一個縮小出屏幕的動畫。

private fun customizeSplashScreenExit() {
    splashScreen.setOnExitAnimationListener { splashScreenView ->
        showSplashExitAnimator(splashScreenView)
    }
}

private fun showSplashExitAnimator(splashScreenView: SplashScreenView) {
    val path = Path()
    path.moveTo(1.0f, 1.0f)
    path.lineTo(0f, 0f)
    val scaleOut = ObjectAnimator.ofFloat(
        splashScreenView,
        View.SCALE_X,
        View.SCALE_Y,
        path
    )
    ...
    scaleOut.doOnEnd {
        splashScreenView.remove()
    }
    scaleOut.start()
}
複製代碼

在這裏插入圖片描述

又或者從上方平移出屏幕的動畫。

private fun showSplashExitAnimator(splashScreenView: SplashScreenView) {
    val slideUp = ObjectAnimator.ofFloat(
        splashScreenView,
        View.TRANSLATION_Y,
        0f,
        -splashScreenView.height.toFloat()
    )
    ...
    slideUp.start()
}
複製代碼

在這裏插入圖片描述

3.3 定製圖標的退出動畫

固然也能夠給圖標單獨加上動畫,好比將Icon上滑。

private fun customizeSplashScreenExit() {
    splashScreen.setOnExitAnimationListener { splashScreenView ->
        showSplashIconExitAnimator(splashScreenView)
    }
}

private fun showSplashIconExitAnimator(splashScreenView: SplashScreenView) {
    val iconView = splashScreenView.iconView ?: return
    val slideUp = ObjectAnimator.ofFloat(
        splashScreenView.iconView,
        View.TRANSLATION_Y,
        0f,
        -iconView.height * 2.toFloat()
    )
    ...
    slideUp.start()
}
複製代碼

在這裏插入圖片描述

3.4 退出動畫的適當時長

針對退出動畫的定製官方還有一段補充說明。

By the start of this callback, the animated vector drawable on the splash screen has begun. Depending on the duration of the app launch, the drawable might be in the middle of its animation. Use SplashScreenView.getIconAnimationStart to know when the animation started. You can calculate the remaining duration of the icon animation.

簡言之,退出畫面回調的時候Icon動畫可能進行到了一半,最好計算Icon動畫的剩餘時長來執行退出動畫。

緣由在於設備性能會影響App描畫的遲早,而第一幀描畫的時候上述的退出回調將被執行。也就是說,性能的優劣會影響啓動畫面退出的回調時機。

  • 性能好的話,畫面退出的回調較早。此時Icon動畫尚在進行當中,能夠將Icon動畫的預設時長的剩餘時間交接給退出效果來執行
  • 性能差的話,畫面退出的回調稍晚。Icon動畫早已經結束,爲了讓用戶儘早看到畫面內容,就不應再執行退出效果了而是直接退出

不能爲了展現效果而讓用戶久等,不然會弄巧成拙。

藉助SplashScreenView的iconAnimationStartMillisiconAnimationDurationMillis方法能夠推算出Icon動畫的剩餘時長。

*模擬器上運行的緣故,大部分時候個人Demo在啓動畫面退出的時候Icon動畫都結束了,少部分狀況下動畫還剩餘一點時間,可能實機的狀況會不同。

private fun showSplashIconExitAnimator(splashScreenView: SplashScreenView) {
    slideUp.duration = getRemainingDuration(splashScreenView)
    ...
}

fun getRemainingDuration(splashScreenView: SplashScreenView): Long  {
    // 取得Icon動畫的時長
    val animationDuration = splashScreenView.iconAnimationDurationMillis
    // 取得Icon動畫的開始時刻
    val animationStart = splashScreenView.iconAnimationStartMillis

    // 再結合當前時間計算出Icon動畫的剩餘時長
    // 1. 時長爲負則固定爲0ms即直接退出
    // 2. 時長爲正則採用該時長執行退出動畫
    return if (animationDuration != null && animationStart != null) {
        (animationDuration - SystemClock.uptimeMillis() + animationStart)
        .coerceAtLeast(0L)
    } else {
        0L
    }
}
複製代碼

4 SplashScreen相關API

4.1 類和接口

類/接口 做用
SplashScreen 啓動畫面管理接口,經過Activity#getSplashScreen取得
OnExitAnimationListener 啓動畫面退出的回調接口,經過SplashScreen#setOnExitAnimationListener註冊
SplashScreenView 啓動畫面包含的視圖,用以定製總體或Icon的退出動畫

4.2 屬性

attr 做用 備註
splashScreenTheme 指定SplashScreen相關的Style 存在一點問題好比brand圖片會不顯示
windowSplashScreenBackground 定製啓動畫面的背景 默認從windowBackground裏讀取
windowSplashScreenBrandingImage 指定啓動畫面底部的品牌圖標 -
windowSplashScreenAnimatedIcon 指定Icon,支持靜態或動畫Drawable -
windowSplashScreenAnimationDuration 指定動畫Icon時長 上限1000ms
windowSplashScreenIconBackgroundColor 補充Icon背景色 -

注意:windowSplashscreenContent是8.0版本新增的定製啓動畫面的屬性,自12開始廢棄了,使用windowSplashscreenAnimatedIcon替代

4.3 SplashScreen的構成

構成示意圖

5 注意

須要嚐鮮SplashScreen的話,須要在Android 12上開發,並作以下必要配置。

  • compileSdkVersion和targetSdkVersion聲明爲S

  • android:exported="true",明示聲明啓動畫面的可見性,不然會安裝失敗

另外啓動頁的Icon不管是靜態的仍是動畫效果的,都應遵循Adaptive Icon的規範,否則Icon會發生變形。

6 結語

Android 12上全新的SplashScreen API很是簡單清晰,整個定製過程很是流暢!

相信在全新的API加持下,APP的啓動畫面能夠迸發出更多特點的、好玩的創意。

快快嘗試起來,給你的用戶留下第一眼的好印象~

本文DEMO

github.com/ellisonchan…

參考資料

歡迎體驗 | Android 12 開發者預覽版 3

SplashScreen的官方文檔

SplashScreen API

SplashScreen相關attr

推薦閱讀

全面覆盤Android開發者容易忽視的Backup功能

Jetpack Hilt有哪些改善又有哪些限制?

Dagger2和它在SystemUI上的應用

相關文章
相關標籤/搜索