Android横屏时BottomSheetDialog为何绘制在导航栏下方被遮挡
问题描述
开发简单Android模态底部弹窗菜单时,竖屏模式下弹窗显示完全正常,但设备旋转至横屏模式后,底部弹窗的底部区域会绘制在导航栏下方,对应位置的内容被隐藏。
复现测试环境:Pixel C平板模拟器,系统API版本为32。
- 竖屏模式:显示效果正常

- 横屏模式:弹窗底部内容被隐藏

本次复现所用示例代码基于Android Studio的「Empty Activity」模板项目创建,实现逻辑参考Material官方文档中Modal Bottom Sheet的开发指引,核心代码如下:
Kotlin核心代码
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.showDialog.setOnClickListener { showBottomSheetDialog() } } private fun showBottomSheetDialog() { val modalBottomSheet = ModalBottomSheet() modalBottomSheet.show(supportFragmentManager, ModalBottomSheet.TAG) } } class ModalBottomSheet : BottomSheetDialogFragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? = inflater.inflate(R.layout.bottom_sheet_dialog, container, false) companion object { const val TAG = "ModalBottomSheet" } }
弹窗布局文件 bottom_sheet_dialog.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/text_view_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="30dp" android:paddingVertical="12dp" android:text="First Row" android:textSize="16sp" /> <TextView android:id="@+id/text_view_2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="30dp" android:paddingVertical="12dp" android:text="Second Row" android:textSize="16sp" /> <TextView android:id="@+id/text_view_3" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="30dp" android:paddingVertical="12dp" android:text="Third Row" android:textSize="16sp" /> </LinearLayout>
解决方案
这个问题是Material组件BottomSheetDialogFragment在高版本系统横屏场景下的窗口边距适配bug:弹窗没有自动计算系统导航栏占用的高度,导致内容绘制到导航栏下方。两种可直接落地的修复方案:
方案1:代码层适配窗口insets(推荐,无布局侵入)
在ModalBottomSheet类中重写onStart方法,手动给弹窗根布局添加导航栏高度的底部内边距:
override fun onStart() { super.onStart() val bottomSheetDialog = dialog as? BottomSheetDialog ?: return val bottomSheetContainer = bottomSheetDialog.findViewById<FrameLayout>( com.google.android.material.R.id.design_bottom_sheet ) ?: return ViewCompat.setOnApplyWindowInsetsListener(bottomSheetContainer) { view, insets -> val navigationBarInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars()) view.setPadding( view.paddingLeft, view.paddingTop, view.paddingRight, navigationBarInsets.bottom ) insets } }
方案2:布局层开启系统边距适配
给弹窗布局的根LinearLayout添加fitsSystemWindows属性,让系统自动为布局预留系统栏占用空间:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:fitsSystemWindows="true"> <!-- 原有子View内容保持不变 --> </LinearLayout>
注意:使用方案2需要将项目的Material组件依赖升级到1.6.0及以上版本,低版本Material库在横屏场景下对fitsSystemWindows的适配存在兼容问题。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

