Android 11下CoordinatorLayout实现全屏时状态栏留白及Insets回调不触发问题
Android 11 全屏沉浸模式适配问题解决方案
问题背景
在Android 11系统上使用全屏沉浸模式时出现适配问题,主Activity布局结构如下:
<DrawerLayout .... android:fitsSystemWindows="true"> <CoordinatorLayout> <AppBarLayout> <FragmentContainerView>
需要在Fragment中开启全屏模式,Android 11之前的版本使用如下方法隐藏状态栏:
fun hideStatusBar (activity: AppCompatActivity?) { activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) }
适配Android 11后修改为:
fun hideStatusBar(activity: AppCompatActivity?) { @Suppress("DEPRECATION") if (isAtLeastAndroid11()) { val controller = activity?.window?.insetsController controller?.hide(WindowInsets.Type.statusBars()) } else { activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) } }
上述代码可以成功隐藏状态栏,但屏幕顶部原状态栏位置会留下一块空白区域。
尝试在Fragment内监听Window Insets调整Fragment容器边距,代码如下:
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if(isAtLeastAndroid11()){ WindowCompat.setDecorFitsSystemWindows(requireActivity().window, false) setUiWindowInsets() } } private fun setUiWindowInsets() { ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets -> posTop = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top posBottom = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom rootView.updateLayoutParams<ViewGroup.MarginLayoutParams> { updateMargins( top = posTop, bottom = posBottom) } insets } }
但ViewCompat.setOnApplyWindowInsetsListener始终没有被回调,原因是CoordinatorLayout会消费onApplyWindowInsets回调,其子View无法收到该事件,Fragment的根布局(RelativeLayout)位于布局层级的FragmentContainer内。
问题1:如何让Fragment中设置的setOnApplyWindowInsetsListener成功收到回调?
- 调整上层布局的
fitsSystemWindows属性:将DrawerLayout、CoordinatorLayout、AppBarLayout的android:fitsSystemWindows全部设置为false,避免上层控件提前消费WindowInsets事件,让Insets可以向下分发到Fragment的根布局。 - 主动触发Insets分发:在给Fragment根布局设置
setOnApplyWindowInsetsListener之后,调用rootView.requestApplyInsets(),主动请求系统重新分发Insets事件。 - 手动分发Insets:如果不需要修改全局布局属性,可以给CoordinatorLayout单独设置
OnApplyWindowInsetsListener,拿到Insets对象后手动调用子View的dispatchApplyWindowInsets方法,将事件向下传递给Fragment容器。
问题2:状态栏隐藏时如何让CoordinatorLayout占满整个屏幕?
- 确保CoordinatorLayout的
fitsSystemWindows属性为false,避免系统自动给CoordinatorLayout添加等同于状态栏高度的顶部padding。 - 隐藏状态栏后手动清除CoordinatorLayout的顶部padding,代码为
coordinatorLayout.setPadding(0, 0, 0, 0),消除原有预留的状态栏空白区域。 - 调整Insets处理逻辑:当状态栏隐藏时,
insets.getInsets(WindowInsetsCompat.Type.statusBars()).top会返回0,此时不需要给Fragment根布局添加顶部margin,内容自然可以延伸到原状态栏位置,实现全屏效果。
内容的提问来源于stack exchange,提问作者Madhan
相关产品推荐
相关产品推荐

