从 Android 12 开始,在所有应用的冷启动和温启动期间,系统一律会应用 Android 系统的默认启动画面。默认情况下,此系统默认启动画面由应用的启动器图标元素和主题的 windowBackground(如果是单色)构成。
注:实际测试发现如果 windowBackground 为一张图片,则会从这种图里提取出单色。
假如有一个 SplashActivity 使用了这样的主题(img_splash 为一张有图片文字的图):
<style name="Theme.SplashTest.Splash" parent="Theme.SplashTest"><item name="windowActionBar">false</item><item name="windowNoTitle">true</item><item name="android:windowFullscreen">true</item><item name="android:windowContentOverlay">@null</item><item name="android:windowBackground">@drawable/img_splash</item></style>
在 Android 10 上冷启动:
(传不了 gif,后续补图)
在 Android 12 上冷启动(可以看到没有显示背景图,而是显示从背景图里提取出的单色):
(传不了 gif,后续补图)
根据 SplashScreen compat 库推荐的迁移方案更新代码:
android {compileSdkVersion 31...}dependencies {...implementation 'androidx.core:core-splashscreen:1.0.0-alpha01'}
<style name="Theme.SplashTest.Starting" parent="Theme.SplashScreen">// Set the splash screen background, animated icon, and animation duration.<item name="windowSplashScreenBackground">@color/purple_500</item>// Use windowSplashScreenAnimatedIcon to add either a drawable or an// animated drawable. One of these is required.<item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item><item name="windowSplashScreenAnimationDuration">200</item> # Required for# animated icons// Set the theme of the Activity that directly follows your splash screen.<item name="postSplashScreenTheme">@style/Theme.SplashTest.Splash</item> # Required.</style>```将 SplashActivity 的 theme 由 Theme.SplashScreen 改为 Theme.SplashTest.Starting。```kotlinoverride fun onCreate(savedInstanceState: Bundle?) {// Handle the splash screen transition.val splashScreen = installSplashScreen()super.onCreate(savedInstanceState)binding = ActivitySplashBinding.inflate(layoutInflater)setContentView(binding.root)...}
在启动 activity 中,先调用 installSplashScreen,然后再调用 setContentView。
splashScreen.setKeepVisibleCondition {// e.g: return true until config is loaded}
可以对 SplashScreen 设置保持可见的条件,默认是一直返回 false。
splashScreen.setOnExitAnimationListener {...}
还可以对 SplashScreen 设置退出监听器,默认是 null。
在 Android 10 上冷启动:
(传不了 gif,后续补图)
在 Android 12 上冷启动:
(传不了 gif,后续补图)
可以看到启动画面外观和风格是一致的。
缺点:
在 Android 12 之前的系统上,闪屏图 不支持 Animated Vector Drawable 动画(测试发现在 Android 12 上也不支持,可能是 bug …)。
Prior API 31, the platform behavior is replicated with the exception of the Animated Vector Drawable support on the launch screen.
(其实目前测试在 Android 12 上也显示不了 AVD 动画。。。)无法对 闪屏图 设置点击监听以跳转到指定页面。
原理:
本质上是先将 Activity 的 Theme 设置为 Theme.SplashScreen,启动后再设置回 postSplashScreenTheme。
open fun install() {...setPostSplashScreenTheme(currentTheme, typedValue)}protected fun setPostSplashScreenTheme(currentTheme: Resources.Theme,typedValue: TypedValue) {if (currentTheme.resolveAttribute(R.attr.postSplashScreenTheme, typedValue, true)) {finalThemeId = typedValue.resourceIdif (finalThemeId != 0) {activity.setTheme(finalThemeId)}}}
设置 splashScreen.setKeepVisibleCondition 是延迟 Activity 设置回 postSplashScreenTheme 后的第一帧绘制。
open fun setKeepVisibleCondition(keepOnScreenCondition: KeepOnScreenCondition) {splashScreenWaitPredicate = keepOnScreenConditionval contentView = activity.findViewById<View>(android.R.id.content)val observer = contentView.viewTreeObserverobserver.addOnPreDrawListener(object : OnPreDrawListener {override fun onPreDraw(): Boolean {if (splashScreenWaitPredicate.shouldKeepOnScreen()) {return false}contentView.viewTreeObserver.removeOnPreDrawListener(this)mSplashScreenViewProvider?.let(::dispatchOnExitAnimation)return true}})}
结论:
由于 windowSplashScreenAnimatedIcon 支持设置 闪屏图 或者 闪屏动画,以及 splashScreen.setKeepVisibleCondition 支持条件等待退出,实际上可以移除专有的 SplashActivity,将 splashScreen 应用在业务主 Activity 上。