DrawerLayout与手势冲突时setSystemGestureExclusionRects在Realme机型不生效如何解决
问题原因
- 最核心的错误是手势排除区域使用了全局屏幕坐标,而非当前View的相对坐标:
systemGestureExclusionRects要求传入的Rect坐标是相对于你调用该方法的View自身的左上角,不是全局屏幕坐标。你用屏幕高度计算的区域如果和当前View的实际布局位置不匹配,就会出现识别位置偏移的问题,这也是你修改参数无效、区域跑到左上角的核心原因。 - 多余的
onDraw调用:onDraw是高频触发的绘制生命周期,在这里反复更新排除区域属于冗余操作,还可能导致不必要的重绘。 - 部分国产ROM(包括Realme UI)对系统手势排除逻辑做了定制修改,原生API的调用逻辑需要配合ROM特性做调整。
修复方案
- 修正坐标计算逻辑,改用当前View自身的尺寸计算排除区域,不要使用全局屏幕尺寸:
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { super.onLayout(changed, l, t, r, b) if (changed) { updateGestureExclusion() } } // 移除onDraw中的updateGestureExclusion调用,不需要在这里触发 private fun updateGestureExclusion() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { return } systemGestureExclusionRects = listOf(createSystemGestureExclusionRect()) } private fun createSystemGestureExclusionRect(): Rect { // 用当前View自身的高度计算,不要用屏幕全局高度 val viewHeight = height val heightInDp = SizeUtils.px2dp(viewHeight.toFloat()) val excludeWidth = SizeUtils.dp2px(56f) return if (heightInDp <= 200) { Rect(0, 0, excludeWidth, viewHeight) } else { val topInDp = (heightInDp - 200) / 2f val top = SizeUtils.dp2px(topInDp) val bottom = top + SizeUtils.dp2px(200f) Rect(0, top, excludeWidth, bottom) } }
- 优先用官方内置适配:如果你使用的是AndroidX的DrawerLayout,升级到
androidx.drawerlayout:drawerlayout:1.2.0及以上版本,该版本已经内置了系统手势返回的冲突适配,不需要手动编写排除区域代码即可自动处理冲突。 - 验证调试:开启开发者选项中的「显示手势排除区域」开关,可直接在屏幕上看到你设置的排除区域的实际位置,快速验证坐标是否正确。
内容的提问来源于stack exchange,提问作者ZSpirytus
相关产品推荐
相关产品推荐

