fix(android): fix keyboard dismiss issue with backdrop (#351)

This commit is contained in:
lodev09 2025-12-25 22:59:27 +08:00
parent b09440d548
commit dee02e15ea
No known key found for this signature in database
GPG Key ID: F098AE8F7143F3E0
4 changed files with 47 additions and 9 deletions

View File

@ -71,7 +71,7 @@ jobs:
runs-on: macos-latest
env:
XCODE_VERSION: 16.3
XCODE_VERSION: latest-stable
TURBO_CACHE_DIR: .turbo/ios
RCT_USE_RN_DEP: 1
RCT_USE_PREBUILT_RNCORE: 1

View File

@ -35,6 +35,7 @@ import com.lodev09.truesheet.core.TrueSheetDimViewDelegate
import com.lodev09.truesheet.core.TrueSheetKeyboardObserver
import com.lodev09.truesheet.core.TrueSheetKeyboardObserverDelegate
import com.lodev09.truesheet.core.TrueSheetStackManager
import com.lodev09.truesheet.utils.KeyboardUtils
import com.lodev09.truesheet.utils.ScreenUtils
// =============================================================================
@ -318,8 +319,10 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
isPresented = false
isSheetVisible = false
wasHiddenByModal = false
isKeyboardTransitioning = false
isPresentAnimating = false
lastEmittedPositionPx = -1
detentIndexBeforeKeyboard = -1
shouldAnimatePresent = true
}
@ -407,6 +410,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
if (isDismissing) return
isDismissing = true
dismissKeyboard()
emitWillDismissEvents()
finishDismiss()
return
@ -471,8 +475,6 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
delegate?.viewControllerDidDragEnd(detentInfo.index, detentInfo.position, detent)
if (detentInfo.index != currentDetentIndex) {
presentPromise?.invoke()
presentPromise = null
currentDetentIndex = detentInfo.index
setupDimmedBackground(detentInfo.index)
delegate?.viewControllerDidChangeDetent(detentInfo.index, detentInfo.position, detent)
@ -665,6 +667,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
if (isDismissing) return
isDismissing = true
dismissKeyboard()
emitWillDismissEvents()
if (animated) {
@ -675,6 +678,10 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
}
}
private fun dismissKeyboard() {
KeyboardUtils.dismiss(reactContext)
}
private fun dismissOrCollapseToLowest() {
if (dismissible) {
dismiss(animated = true)
@ -845,7 +852,8 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
fun updateDimAmount(sheetTop: Int? = null, animated: Boolean = false) {
if (!dimmed) return
val top = (sheetTop ?: sheetView?.top ?: return) + currentKeyboardInset
val keyboardOffset = if (isDismissing) 0 else currentKeyboardInset
val top = (sheetTop ?: sheetView?.top ?: return) + keyboardOffset
if (animated) {
val targetAlpha = dimView?.calculateAlpha(
@ -912,7 +920,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
override fun keyboardWillHide() {
if (!shouldHandleKeyboard()) return
setupSheetDetents()
if (detentIndexBeforeKeyboard >= 0) {
if (!isDismissing && detentIndexBeforeKeyboard >= 0) {
setStateForDetentIndex(detentIndexBeforeKeyboard)
detentIndexBeforeKeyboard = -1
}

View File

@ -8,6 +8,7 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsAnimationCompat
import androidx.core.view.WindowInsetsCompat
import com.facebook.react.uimanager.ThemedReactContext
import com.lodev09.truesheet.utils.KeyboardUtils
interface TrueSheetKeyboardObserverDelegate {
fun keyboardWillShow(height: Int)
@ -59,7 +60,7 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
}
}
private fun getKeyboardHeight(insets: WindowInsetsCompat?): Int = insets?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
private fun getKeyboardHeight(): Int = KeyboardUtils.getKeyboardHeight(targetView)
private fun setupAnimationCallback() {
ViewCompat.setWindowInsetsAnimationCallback(
@ -69,14 +70,14 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
private var endHeight = 0
override fun onPrepare(animation: WindowInsetsAnimationCompat) {
startHeight = getKeyboardHeight(ViewCompat.getRootWindowInsets(targetView))
startHeight = getKeyboardHeight()
}
override fun onStart(
animation: WindowInsetsAnimationCompat,
bounds: WindowInsetsAnimationCompat.BoundsCompat
): WindowInsetsAnimationCompat.BoundsCompat {
endHeight = getKeyboardHeight(ViewCompat.getRootWindowInsets(targetView))
endHeight = getKeyboardHeight()
targetHeight = endHeight
isHiding = endHeight < startHeight
if (endHeight > startHeight) {
@ -99,7 +100,7 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
}
override fun onEnd(animation: WindowInsetsAnimationCompat) {
val finalHeight = getKeyboardHeight(ViewCompat.getRootWindowInsets(targetView))
val finalHeight = getKeyboardHeight()
updateHeight(startHeight, finalHeight, 1f)
if (isHiding) {
delegate?.keyboardDidHide()

View File

@ -0,0 +1,29 @@
package com.lodev09.truesheet.utils
import android.content.Context
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.facebook.react.uimanager.ThemedReactContext
object KeyboardUtils {
/**
* Dismisses the soft keyboard if currently shown.
*/
fun dismiss(reactContext: ThemedReactContext) {
val imm = reactContext.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
reactContext.currentActivity?.currentFocus?.let { focusedView ->
imm?.hideSoftInputFromWindow(focusedView.windowToken, 0)
}
}
/**
* Gets the current keyboard height from window insets.
*/
fun getKeyboardHeight(view: View): Int {
val insets = ViewCompat.getRootWindowInsets(view)
return insets?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
}
}