ViewCompat嵌入监听器在旧版API中返回错误值,无法感知状态栏变化
解决旧API下ViewCompat.setOnApplyWindowInsetsListener不更新状态栏Insets的问题
问题分析
在API 23/25等旧版本设备上,切换沉浸式模式时,ViewCompat.setOnApplyWindowInsetsListener不会自动触发Insets更新——旧系统的系统UI可见性变化事件与新的WindowInsetsCompat.Type机制没有自动关联,导致嵌入值和可见性始终停留在初始状态。而废弃的setOnSystemUiVisibilityChangeListener能正常感知变化,是因为它直接监听旧系统的原生UI可见性回调。
解决方案
结合旧API的系统UI可见性监听手动触发Insets重新计算,同时修正Insets监听器的返回值逻辑:
1. 添加旧API的系统UI可见性监听
在Activity的onCreate()中,针对旧版本系统添加监听,触发Insets重新计算:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { window.decorView.setOnSystemUiVisibilityChangeListener { _ -> // 强制触发Insets监听器回调 ViewCompat.requestApplyInsets(window.decorView) } }
2. 修正Insets监听器的返回值
保留原有的ViewCompat.setOnApplyWindowInsetsListener,但返回ViewCompat.onApplyWindowInsets(view, insets),确保系统能正常处理后续的Insets传递:
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { view, insets -> val statusbarInsets = insets.getInsets(WindowInsetsCompat.Type.statusBars()) val isStatusBarVisible = insets.isVisible(WindowInsetsCompat.Type.statusBars()) Timber.d("Listener status insets: $statusbarInsets, bar visible: $isStatusBarVisible") // 让系统继续处理Insets,避免阻断其他View的布局逻辑 ViewCompat.onApplyWindowInsets(view, insets) }
原理说明
- 旧API(< Android 11)中,系统UI可见性变化不会主动通知
WindowInsetsCompat的监听器,需要通过ViewCompat.requestApplyInsets()手动触发重新计算。 - 返回
ViewCompat.onApplyWindowInsets(view, insets)而非原始insets或WindowInsetsCompat.CONSUMED,能保证系统默认的Insets处理逻辑正常执行,避免影响其他View的布局适配。
内容的提问来源于stack exchange,提问作者Jorge Guillermo Negrete
相关产品推荐
相关产品推荐

