Android 12上全新的應用啓動畫面,還不適配一下? 1前言 2定製進入效果 3 定製退出效果 4 SplashScreen相關API 5 注意 6 結語 本文DEMO 參考資料 推薦學習

這是我見過一個對Android 12 分析挺用心的CSDN博主。
原文地址:https://blog.csdn.net/allisonchen/article/details/116166124

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

在App的主要內容展示之前,按照需求的不同,或多或少會先展示這樣幾個畫面。

1前言

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

1.一般通過設置windowSplashscreenContent屬性來展示UI提供的啓動圖,系統將爲它創建專門的Window

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

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

4.最終發現windowDisablePreview屬性可以徹底關閉這個畫面,這樣一來確實沒有任何突兀的畫面一閃而過了

但這又會帶來啓動"變慢"的副作用,因爲用來過渡的啓動畫面被關閉之後,App描畫前屏幕幾乎沒有什麼變化。即便App性能沒有劣化,但爲了留住用戶,我們還是得好好對待這個啓動畫面。

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

有了這個全新特性的幫助,啓動畫面的定製將更加自由、方便。先來看下采用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 定製整體的退出動畫

可以給啓動畫面的整體設置TRANSLATESCALEROTATE、ALPHA`等各種動畫,使得退出更加自然。

比如給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 類和接口

4.2 屬性

注意: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

https://github.com/ellisonchan/SplashScreen

參考資料

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

SplashScreen的官方文檔

SplashScreen API

SplashScreen相關attr

推薦學習

視頻系列:

技術文系列:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章