Search code examples
android-jetpack-compose

How can I detect keyboard opening and closing in jetpack compose?


The only way I've found in compose is to use accompanist-insets and that removes window insets. And such causes other problems with my app's layout.

The Android way seems to be this and I could pass that into my compose app and act accordingly.

Is there another way in jetpack compose?


Solution

  • I found a way with Android's viewTreeObserver. It essentially is the Android version but it calls a callback that can be used in compose.

    class MainActivity : ComponentActivity() {
    
      var kbGone = false
      var kbOpened: () -> Unit = {}
      var kbClosed: () -> Unit = {}
    
      override fun onCreate(state: Bundle?) {
        super.onCreate(state)
        setContent {
          kbClosed = {
            // dismiss the keyboard with LocalFocusManager for example
          }
          kbOpened = {
            // something
          }
          MyComponent()
        }
        setupKeyboardDetection(findViewById<View>(android.R.id.content))
      }
    
      fun setupKeyboardDetection(contentView: View) {
        contentView.viewTreeObserver.addOnGlobalLayoutListener {
          val r = Rect()
          contentView.getWindowVisibleDisplayFrame(r)
          val screenHeight = contentView.rootView.height
          val keypadHeight = screenHeight - r.bottom
          if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
            kbGone = false
            kbOpened()
          } else(!kbGone) {
            kbGone = true
            kbClosed()
          }
        }
      }
    }