Android 12/12L禁用启动页过渡动画后windowLightStatusBar失效求助
问题背景
我配置了Theme.SystemBarColors主题,让系统栏背景在明暗模式下均匹配主题背景,单独使用时各Android版本表现正常。为实现系统启动页与应用内启动页的无缝切换,在Android 12+的onCreate中调用getSplashScreen().setOnExitAnimationListener(SplashScreenView::remove)禁用启动页退出动画,但这导致Android 12/12L上windowLightStatusBar和windowLightNavigationBar属性失效:系统栏背景颜色正常,但文字变为白色搭配浅背景,出现异常显示。该问题仅在系统启动页实际显示时触发(如从桌面启动应用),Android Studio直接启动则无异常,且Android 13中不存在此问题。
主题配置代码(values-v27/styles.xml):
<style name="Theme.SystemBarColors" parent="Theme.AppCompat.DayNight.NoActionBar"> <item name="android:statusBarColor">?android:attr/colorBackground</item> <item name="android:windowLightStatusBar">?attr/isLightTheme</item> <item name="android:navigationBarColor">?android:attr/colorBackground</item> <item name="android:windowLightNavigationBar">?attr/isLightTheme</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowTranslucentNavigation">false</item> <item name="android:windowTranslucentStatus">false</item> </style>
调用的核心代码:
getSplashScreen().setOnExitAnimationListener(SplashScreenView::remove);
解决方案
方案1:手动重新应用系统栏文字颜色属性
直接移除SplashScreenView会打断系统对主题属性的应用流程,因此可以在移除后手动触发系统栏文字颜色的设置:
getSplashScreen().setOnExitAnimationListener { splashView -> // 移除启动页视图 splashView.remove() // 手动重新设置系统栏文字颜色 val window = window val isLightTheme = resources.getBoolean(R.bool.isLightTheme) window.decorView.systemUiVisibility = if (isLightTheme) { View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR } else { 0 } }
需确保isLightTheme在资源文件中正确配置:
- values/bools.xml:
<bool name="isLightTheme">true</bool> - values-night/bools.xml:
<bool name="isLightTheme">false</bool>
方案2:通过空动画完成启动页退出
避免直接调用remove(),而是通过极短的透明动画完成退出流程,让系统正常处理主题属性过渡:
getSplashScreen().setOnExitAnimationListener { splashView -> splashView.animate() .alpha(0f) .setDuration(1) // 视觉上无感知的短时长 .withEndAction { splashView.remove() } .start() }
这种方式既实现了无缝切换的视觉效果,又保证系统完整执行启动页退出的属性应用逻辑。
方案3:针对Android 12/12L做版本适配
仅在Android 12和12L上使用修复逻辑,Android 13及以上保持原有代码:
if (Build.VERSION.SDK_INT in Build.VERSION_CODES.S..Build.VERSION_CODES.S_V2) { getSplashScreen().setOnExitAnimationListener { splashView -> splashView.animate() .alpha(0f) .setDuration(1) .withEndAction { splashView.remove() } .start() } } else { getSplashScreen().setOnExitAnimationListener(SplashScreenView::remove) }
问题原理
Android 12/12L的SplashScreen框架在直接调用remove()时,会提前终止系统栏主题属性的应用流程,导致windowLightStatusBar这类依赖视图树更新的属性未被正确加载。通过延迟手动设置或让动画正常完成,可让系统有足够时间处理这些属性的切换逻辑。
内容的提问来源于stack exchange,提问作者rkjnsn

