Material库Date range picker弹窗遮挡手机系统导航按钮问题
问题描述
当前使用的Material组件库版本如下:com.google.android.material:material:1.7.0-alpha02
调用该库的Material日期选择器展示Date range picker(日期范围选择器)时,选择器弹窗会与手机的系统导航按钮区域发生重叠,异常效果如下图所示:
咨询该问题的产生原因,以及可行的适配修复方案。
回答
问题原因
这个重叠问题是1.7.0-alpha02版本Material组件库的原生Bug:
- 该版本属于未经过全场景适配的测试版本,日期范围选择器弹窗的根布局没有正确处理
WindowInsets边距适配,没有为底部系统导航栏预留对应高度的padding,弹窗内容直接绘制到了导航栏区域,就会出现控件重叠的问题。 - 该问题在采用全面屏手势/自定义高度导航栏的机型(比如截图里的三星S22 Ultra)上复现率极高,因为这类机型的导航栏高度和原生安卓默认值不一致,组件内置的固定边距值不匹配实际高度。
修复方案
按推荐优先级从高到低排列:
- 升级组件库到正式稳定版(最优解)
alpha版本本身存在大量未修复的适配问题,直接把依赖升级到1.7.0及以上的正式稳定版本即可自动修复,不需要额外写适配代码:
// 替换原有1.7.0-alpha02依赖 implementation "com.google.android.material:material:1.9.0"
官方在1.7.0正式版中已经合入了系统栏Insets适配的修复提交,全量兼容手势导航、三键导航场景。
- 固定版本临时适配(无法升级依赖时使用)
如果项目有兼容要求暂时不能升级组件版本,可以通过监听弹窗生命周期手动补边距修复:
第一步先给日期选择器定义单独的弹窗主题,开启系统栏绘制权限:
<style name="ThemeOverlay.DateRangePicker.Fix" parent="ThemeOverlay.MaterialComponents.MaterialCalendar"> <item name="android:windowDrawsSystemBarBackgrounds">true</item> </style>
第二步在构建弹窗实例时,在弹窗显示后主动给根布局添加导航栏高度的底部内边距:
val picker = MaterialDatePicker.Builder.dateRangePicker() .setTheme(R.style.ThemeOverlay_DateRangePicker_Fix) .build() picker.show(supportFragmentManager, "range_picker") // 弹窗显示后执行Insets适配 picker.dialog?.setOnShowListener { val calendarRoot = picker.dialog?.findViewById<ViewGroup>(com.google.android.material.R.id.mtrl_calendar_parent) ?: return@setOnShowListener ViewCompat.setOnApplyWindowInsetsListener(calendarRoot) { view, insets -> val navBarHeight = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom view.updatePadding(bottom = navBarHeight) insets } ViewCompat.requestApplyInsets(calendarRoot) }
Java代码逻辑完全一致,仅语法有区别,核心逻辑就是拿到日历容器布局,动态给底部加上导航栏对应的高度即可。
- 降级到无Bug的稳定版本
如果不想额外写适配代码,也可以直接把组件版本降到没有该Bug的1.6.0正式版:
implementation "com.google.android.material:material:1.6.0"
该方案不推荐,低版本会缺失后续新增的组件特性和安全补丁。
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

