androidkeyboardwindowinsets

How to use WindowInsets API (Compat version) to show/hide keyboard?


I'm playing with WindowInsets API to opening/hiding keyboard, but it seems to doesnt work with Compat version (target API 29) or something.

fun View.hideKeyboard() {
    ViewCompat.getWindowInsetsController(this)?.hide(WindowInsetsCompat.Type.ime())
}

fun View.showKeyboard() {
    ViewCompat.getWindowInsetsController(this)?.show(WindowInsetsCompat.Type.ime())
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<EditText>(R.id.text).showKeyboard()
    }
}

Layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
implementation 'androidx.core:core-ktx:1.6.0-alpha01'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'

Any suggestions?


Solution

  • Referring to WindowInsetsControllerCompat source, here is view.hasWindowFocus() returns false as the window hasn't got focus yet. If set keyboard interaction to buttons then window has time to get focus and everything is OK.

    Here are two ways:

    1. Waiting for focus changing to true with viewTreeObserver.addOnWindowFocusChangeListener:
      editText.viewTreeObserver.addOnWindowFocusChangeListener(
                  object : ViewTreeObserver.OnWindowFocusChangeListener {
                      override fun onWindowFocusChanged(hasFocus: Boolean) {
                          if (hasFocus) {
                              editText.showKeyboard()
                              // show only once
                              editText.viewTreeObserver.removeOnWindowFocusChangeListener(this)
                          }
                      }
                  })
      
    2. Make keyboard is visible when window receives focus:
      window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
      editText.showKeyboard()