Android 6-10(API23-29) WindowInsetsCompat检测IME可见性误返回true问题
WindowInsetsCompat软键盘可见性判断低版本兼容方案
问题表现
使用WindowInsetsCompat.isVisible(WindowInsetsCompat.Type.ime())判断软键盘是否显示时,仅Android 11(API 30)及以上系统返回结果符合预期,Android 6到Android 10(API 23-29)系统即使软键盘未打开,依然会返回true。
问题根因
- Android 11才原生支持IME可见性查询接口,低版本系统没有对应原生实现
- 低版本下
WindowInsetsCompat的isVisible(Type.ime())兼容逻辑存在缺陷,无法通过rootWindowInsets获取准确的软键盘可见状态
兼容实现方案
通过版本分支判断,高版本用官方原生API,低版本通过IME插入高度和导航栏高度的差值做判断:
private fun registerGlobalLayoutListener() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { window.decorView.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener) } } private fun unregisterGlobalLayoutListener() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { window.decorView.viewTreeObserver.removeOnGlobalLayoutListener(globalLayoutListener) } } @RequiresApi(Build.VERSION_CODES.M) private val globalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener { val showingKeyboard = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // Android 11及以上直接使用官方API判断 WindowInsetsCompat.toWindowInsetsCompat(window.decorView.rootWindowInsets) .isVisible(WindowInsetsCompat.Type.ime()) } else { // 低版本通过高度差做兼容判断 val insets = WindowInsetsCompat.toWindowInsetsCompat(window.decorView.rootWindowInsets) val imeBottomInset = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom val navBarHeight = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom // 软键盘显示时IME插入高度会远大于导航栏高度,以此作为判断阈值 imeBottomInset > navBarHeight } viewModel.setKeyboardShowing(showingKeyboard) }
注意事项
- 阈值可根据业务场景调整,无特殊需求也可直接判断
imeBottomInset > 0即可覆盖绝大多数场景 - 如果页面配置了
windowSoftInputMode=adjustNothing,布局不会随软键盘弹出变化,该方案不适用,需结合其他业务逻辑判断
内容的提问来源于stack exchange,提问作者user924
相关产品推荐
相关产品推荐

