Fix crash when using View.hideKeyboardAndAwaitAnimation (#6502)
* Fix crash when using `View.hideKeyboardAndAwaitAnimation` Remove the `View.OnApplyWindowInsetsListener` used in modern Android versions to detect if the insets changed after they do the first time: this is a single use operation and the listener will be called every time the insets change Also, replace `Mutex` with `CompletableDeferred` so it doesn't matter if it's called several times, we only care about the first one. * Don't try to hide the keyboard if it's already hidden. Also, add a 1s timeout in case everything goes wrong and we somehow never complete the future.
This commit is contained in:
parent
dbd51ebc90
commit
786c260fc2
1 changed files with 23 additions and 11 deletions
|
|
@ -16,9 +16,11 @@ import android.view.ViewTreeObserver
|
||||||
import android.view.WindowInsets
|
import android.view.WindowInsets
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
fun View.hideKeyboard() {
|
fun View.hideKeyboard() {
|
||||||
val imm = context?.getSystemService<InputMethodManager>()
|
val imm = context?.getSystemService<InputMethodManager>()
|
||||||
|
|
@ -26,29 +28,39 @@ fun View.hideKeyboard() {
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun View.hideKeyboardAndAwaitAnimation() {
|
suspend fun View.hideKeyboardAndAwaitAnimation() {
|
||||||
val imm = context?.getSystemService<InputMethodManager>()
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !rootWindowInsets.isVisible(WindowInsets.Type.ime())) {
|
||||||
|
// Keyboard is already hidden, no need to do anything
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val mutex = Mutex()
|
val imm = context?.getSystemService<InputMethodManager>() ?: return
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
val future = CompletableDeferred<Unit>()
|
||||||
|
|
||||||
|
val requested = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
setOnApplyWindowInsetsListener { view, insets ->
|
setOnApplyWindowInsetsListener { view, insets ->
|
||||||
if (!insets.isVisible(WindowInsets.Type.ime())) {
|
if (!insets.isVisible(WindowInsets.Type.ime())) {
|
||||||
mutex.unlock()
|
future.complete(Unit)
|
||||||
|
// Remove the listener now, it's a single use operation
|
||||||
|
setOnApplyWindowInsetsListener(null)
|
||||||
}
|
}
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
imm?.hideSoftInputFromWindow(windowToken, 0)
|
imm.hideSoftInputFromWindow(windowToken, 0)
|
||||||
} else {
|
} else {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
imm?.hideSoftInputFromWindow(windowToken, 0, object : ResultReceiver(null) {
|
imm.hideSoftInputFromWindow(windowToken, 0, object : ResultReceiver(null) {
|
||||||
override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
|
override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
|
||||||
if (resultCode == InputMethodManager.RESULT_UNCHANGED_HIDDEN ||
|
if (resultCode == InputMethodManager.RESULT_UNCHANGED_HIDDEN || resultCode == InputMethodManager.RESULT_HIDDEN) {
|
||||||
resultCode == InputMethodManager.RESULT_HIDDEN) {
|
future.complete(Unit)
|
||||||
mutex.unlock()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
mutex.lock()
|
|
||||||
|
if (requested) {
|
||||||
|
// Await the future to ensure the keyboard hide animation has completed before proceeding
|
||||||
|
withTimeoutOrNull(1.seconds) { future.await() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun View.showKeyboard(andRequestFocus: Boolean = false) {
|
fun View.showKeyboard(andRequestFocus: Boolean = false) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue