Compose中快捷监听软键盘收起弹出状态方法(兼容Android各个版本)

  • Post author:
  • Post category:其他


Compose中快捷监听软键盘收起弹出状态方法



非compose方法监听软键盘收起

在我们开发compose项目之前就有很多获取软键盘状态的方法,比如如下法1:

 fun getImeVisible(activity: Activity, callback: WindowsKeyboardCallback? = null) { //判断软键盘是否收起
        ViewCompat.setOnApplyWindowInsetsListener(activity.window.decorView) { _, insets ->
            val imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
            val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
            callback?.onKeyboardChanged(imeVisible, imeHeight)
            WindowInsetsCompat.CONSUMED
        }
    }

但是这种不适合navigation的多页面路由中使用判断,会导致状态栏显示异常。

方法二:

fun Activity.listenForKeyboardVisibilityChange(callback: (Boolean) -> Unit) {
    val rootView = window.decorView.findViewById<View>(android.R.id.content)
    rootView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        private val rect = Rect()
        private var isKeyboardVisible = false

        override fun onGlobalLayout() {
            rootView.getWindowVisibleDisplayFrame(rect)
            val screenHeight = rootView.rootView.height
            val keyboardHeight = screenHeight - rect.bottom

            val isVisible = keyboardHeight > screenHeight * 0.15 // 判断键盘高度是否超过屏幕高度的 15%

            if (isVisible != isKeyboardVisible) {
                isKeyboardVisible = isVisible
                callback(isVisible)
            }
        }
    })
}



在compose中监听软键盘收起状态

    val imeVisible = WindowInsets.Companion.isImeVisible
    LaunchedEffect(WindowInsets.isImeVisible) {
        if (!imeVisible) {
            //软键盘收起
            onSubmit.invoke()
        }
    }

只需要如上的判断既可以监听软键盘状态,而且不会对页面造成影响,可以说是非常简单了,(效果图就不搞了)觉得对你有帮助的也请点个收藏谢谢!

今天同事在测试的时候发现了问题,在Android10(对应29)手机上这个方法不起作用,下面是我最终修改后的代码,做了适配:

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun imeVisible(): State<Boolean> {
    val isImeVisible = remember { mutableStateOf(false) }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        isImeVisible.value = WindowInsets.isImeVisible
    }else {
        val view = LocalView.current
        DisposableEffect(view) {
            val onGlobalListener = ViewTreeObserver.OnGlobalLayoutListener {
                val rect = Rect()
                view.getWindowVisibleDisplayFrame(rect)
                val screenHeight = view.rootView.height
                val keypadHeight = screenHeight - rect.bottom
                isImeVisible.value = keypadHeight > screenHeight * 0.15
            }
            view.viewTreeObserver.addOnGlobalLayoutListener(onGlobalListener)
            onDispose {
                view.viewTreeObserver.removeOnGlobalLayoutListener(onGlobalListener)
            }
        }
    }

    return isImeVisible
}

使用如下:

val imeVisible = imeVisible().value
    LaunchedEffect(imeVisible) {
        if (!imeVisible) {
            onSubmit.invoke()
        }
    }



版权声明:本文为Tobey_r1原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。