Skip to content

Commit 49381b0

Browse files
authored
fix(android): only handle keyboard for focused views within sheet (#365)
* fix(android): only handle keyboard for focused views within sheet * refactor(android): move isKeyboardTransitioning to observer * refactor(android): move isFocusedViewWithinSheet to keyboard observer
1 parent cf86071 commit 49381b0

3 files changed

Lines changed: 38 additions & 11 deletions

File tree

android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
139139

140140
// Keyboard State
141141
private var detentIndexBeforeKeyboard: Int = -1
142-
private var isKeyboardTransitioning: Boolean = false
143142

144143
// Promises
145144
var presentPromise: (() -> Unit)? = null
@@ -238,6 +237,14 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
238237
private val currentKeyboardInset: Int
239238
get() = keyboardObserver?.currentHeight ?: 0
240239

240+
private val isKeyboardTransitioning: Boolean
241+
get() = keyboardObserver?.isTransitioning ?: false
242+
243+
private fun isFocusedViewWithinSheet(): Boolean {
244+
val sheet = sheetView ?: return false
245+
return keyboardObserver?.isFocusedViewWithinSheet(sheet) ?: false
246+
}
247+
241248
val bottomInset: Int
242249
get() = if (edgeToEdgeEnabled) ScreenUtils.getInsets(reactContext).bottom else 0
243250

@@ -320,7 +327,6 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
320327
isPresented = false
321328
isSheetVisible = false
322329
wasHiddenByModal = false
323-
isKeyboardTransitioning = false
324330
isPresentAnimating = false
325331
lastEmittedPositionPx = -1
326332
detentIndexBeforeKeyboard = -1
@@ -872,9 +878,11 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
872878
// MARK: - Keyboard Handling
873879
// =============================================================================
874880

875-
private fun shouldHandleKeyboard(): Boolean {
881+
private fun shouldHandleKeyboard(checkFocus: Boolean = true): Boolean {
876882
if (wasHiddenByModal) return false
877-
return isTopmostSheet
883+
if (!isTopmostSheet) return false
884+
if (checkFocus && !isFocusedViewWithinSheet()) return false
885+
return true
878886
}
879887

880888
fun setupKeyboardObserver() {
@@ -886,25 +894,23 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
886894
keyboardObserver = TrueSheetKeyboardObserver(coordinator, reactContext).apply {
887895
delegate = object : TrueSheetKeyboardObserverDelegate {
888896
override fun keyboardWillShow(height: Int) {
889-
isKeyboardTransitioning = true
890897
if (!shouldHandleKeyboard()) return
891898
detentIndexBeforeKeyboard = currentDetentIndex
892899
setupSheetDetents()
893900
setStateForDetentIndex(detents.size - 1)
894901
}
895902

896903
override fun keyboardWillHide() {
897-
if (!shouldHandleKeyboard()) return
904+
if (!shouldHandleKeyboard(checkFocus = false)) return
905+
898906
setupSheetDetents()
899907
if (!isDismissing && detentIndexBeforeKeyboard >= 0) {
900908
setStateForDetentIndex(detentIndexBeforeKeyboard)
901909
detentIndexBeforeKeyboard = -1
902910
}
903911
}
904912

905-
override fun keyboardDidHide() {
906-
isKeyboardTransitioning = false
907-
}
913+
override fun keyboardDidHide() {}
908914

909915
override fun keyboardDidChangeHeight(height: Int) {
910916
if (!shouldHandleKeyboard()) return

android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ interface TrueSheetKeyboardObserverDelegate {
2121
* Tracks keyboard height and notifies delegate on changes.
2222
* Uses WindowInsetsAnimationCompat on API 30+, ViewTreeObserver fallback on older versions.
2323
*/
24-
class TrueSheetKeyboardObserver(private val targetView: View, private val reactContext: ThemedReactContext) {
24+
class TrueSheetKeyboardObserver(
25+
private val targetView: View,
26+
private val reactContext: ThemedReactContext
27+
) {
2528

2629
var delegate: TrueSheetKeyboardObserverDelegate? = null
2730

@@ -31,6 +34,20 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
3134
var targetHeight: Int = 0
3235
private set
3336

37+
var isTransitioning: Boolean = false
38+
private set
39+
40+
fun isFocusedViewWithinSheet(sheetView: View): Boolean {
41+
val focusedView = reactContext.currentActivity?.currentFocus ?: return false
42+
var current: View? = focusedView
43+
while (current != null && current !== targetView) {
44+
if (current === sheetView) return true
45+
val parent = current.parent
46+
current = if (parent is View) parent else null
47+
}
48+
return false
49+
}
50+
3451
private var isHiding: Boolean = false
3552
private var globalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null
3653
private var activityRootView: View? = null
@@ -80,6 +97,7 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
8097
endHeight = getKeyboardHeight()
8198
targetHeight = endHeight
8299
isHiding = endHeight < startHeight
100+
isTransitioning = true
83101
if (endHeight > startHeight) {
84102
delegate?.keyboardWillShow(endHeight)
85103
} else if (isHiding) {
@@ -102,6 +120,7 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
102120
override fun onEnd(animation: WindowInsetsAnimationCompat) {
103121
val finalHeight = getKeyboardHeight()
104122
updateHeight(startHeight, finalHeight, 1f)
123+
isTransitioning = false
105124
if (isHiding) {
106125
delegate?.keyboardDidHide()
107126
isHiding = false
@@ -134,6 +153,7 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
134153
targetHeight = newHeight
135154
isHiding = newHeight < previousHeight
136155

156+
isTransitioning = true
137157
if (newHeight > previousHeight) {
138158
delegate?.keyboardWillShow(newHeight)
139159
} else if (isHiding) {
@@ -142,6 +162,7 @@ class TrueSheetKeyboardObserver(private val targetView: View, private val reactC
142162

143163
// On legacy API, keyboard has already animated - just update immediately
144164
updateHeight(previousHeight, newHeight, 1f)
165+
isTransitioning = false
145166

146167
if (isHiding && newHeight == 0) {
147168
delegate?.keyboardDidHide()

example/shared/src/screens/ModalScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ export const ModalScreen = ({ onNavigateToTest, onDismiss }: ModalScreenProps) =
1818
return (
1919
<TrueSheetProvider>
2020
<View style={styles.content}>
21-
<Button text="Dismiss Modal" onPress={onDismiss} />
2221
<View style={styles.heading}>
2322
<Text style={styles.title}>Modal Screen</Text>
2423
<Text style={styles.subtitle}>
2524
This is a fullScreenModal opened from a TrueSheet. You can present sheets from here too!
2625
</Text>
2726
</View>
2827
<Input />
28+
<Button text="Dismiss Modal" onPress={onDismiss} />
2929
<Button text="TrueSheet Prompt" onPress={() => promptSheet.current?.present()} />
3030
<Button text="TrueSheet FlatList" onPress={() => flatlistSheet.current?.present()} />
3131
<Spacer />

0 commit comments

Comments
 (0)