找了一会,Android好像是没有提供一个像是系统广播、onBackPressed()或者KeyEvent之类的东西来提供系统软键盘的弹出和收回的
但是,WindowInsetsCompat
和OnApplyWindowInsetsListener
这两个玩意是可以做到实现监听键盘显示和隐藏的
KEYBOARD
是一个WindowInsetsCompat.Type
实例,用于表示IME,还有其他的类型可以去源码看一下
具体实现如下:
registerKeyboardListener
函数
这个函数用于注册一个监听器,当键盘显示或隐藏时会调用传入的block
。
• window
:当前的Window
实例。
• block
当键盘状态变化时会被调用,view是当前焦点的View,还有一个布尔值用于判断。函数内部是先拿到rootView
,然后设置一个OnApplyWindowInsetsListener
来监听窗口内陷的变化。当键盘显示或隐藏时,它会检查当前焦点的View
,并调用传入的block
。
private val KEYBOARD = WindowInsetsCompat.Type.ime()
fun registerKeyboardListener(window: Window?, block: (currentFocusView: View?, imeVisible: Boolean) -> Unit) {
window?.decorView?.rootView?.let { windowView ->
windowView.post {// Add this case there are input comp in 2 consecutive pages(unregisterKeyboardListener method will invoke after the register invoke)
Log.d("KeyboardUtils","KeyboardListener==>register@${windowView.hashCode()}")
val listener = androidx.core.view.OnApplyWindowInsetsListener { view, insets ->
window.currentFocus?.let { currentFocus ->
val imeVisible = insets.isVisible(KEYBOARD)
Log.d("KeyboardUtils","KeyboardListener==>keyboardShown:$imeVisible")
block.invoke(currentFocus, imeVisible)
}
//cannot return insets,must returns as below:
ViewCompat.onApplyWindowInsets(view, insets)
}
ViewCompat.setOnApplyWindowInsetsListener(windowView, listener)
}
}
}
fun unregisterKeyboardListener(window: Window?) {
window?.decorView?.rootView?.let { windowView ->
ViewCompat.setOnApplyWindowInsetsListener(windowView, null)
Log.d("KeyboardUtils","KeyboardListener==>unregister@${windowView.hashCode()}")
}
}
fun getSystemWindow(fragment: Fragment?, isEmbeddedFragment: Boolean = false): Window? {
val windowFragment = if (isEmbeddedFragment) {
fragment?.parentFragment
} else {
fragment
}
val window: Window? = if (windowFragment is DialogFragment) {
windowFragment.dialog?.window
} else {
windowFragment?.activity?.window
}
return window
}