Skip to content

Commit 84ac214

Browse files
authored
fix: compare size in onApplyWindowInsets (#268)
## 📜 Description Compare size of keyboard in `onApplyWindowInsets` callback. ## 💡 Motivation and Context When you have an opened keyboard and you trigger a navigation from screen A to screen B, then you'll have a race condition between `onApplyWindowInsets` and `onStart`/`onProgress`/`onEnd` callbacks. For this particular case `onApplyWindowInsets` shouldn't emit events, because in this method I'm simply detecting keyboard resize. With old condition if-statement: ```kt if (isKeyboardShown && !isMoving && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) ``` is evaluated as `true` and because of that we're dispatching unnecessary events. Since this method was designed to detect keyboard layout changes/resizing I thought that it would be good to add additional condition that compares previous and current height. With this fix the race condition will gone, because keyboard is not changes its size when you perform navigation. Another case that would be solved by this PR is when you open a keyboard, let your screen to dim (become fully dark/turned off, but not to be locked yet), and touch it to wake your phone - in this case `onApplyWindowInsets` is also dispatching and before we were sending unnecessary events. Now it'll not happen, because size of the keyboard is the same 🙃 Closes #267 ## 📢 Changelog ### Android - changed `DEFAULT_ANIMATION_TIME` to int; - added `isKeyboardSizeEqual` variable; - used `isKeyboardSizeEqual` variable as `!isKeyboardSizeEqual` in if-statement. ## 🤔 How Has This Been Tested? Tested manually on Pixel 3A (API 33). ## 📸 Screenshots (if appropriate): |Before|After| |-------|-----| |<video src="https://github.com/kirillzyusko/react-native-keyboard-controller/assets/22820318/3c36fe8a-1a73-4f8b-8220-de4757f6fa85">|<video src="https://github.com/kirillzyusko/react-native-keyboard-controller/assets/22820318/cd4f9c2b-c013-46e5-8e5d-a41e9b5f51f0">| ## 📝 Checklist - [x] CI successfully passed
1 parent 35570f9 commit 84ac214

File tree

1 file changed

+16
-8
lines changed

1 file changed

+16
-8
lines changed

android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt

+16-8
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class KeyboardAnimationCallback(
110110
* - we dispatch `keyboardDidShow` (onEnd).
111111
*/
112112
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
113+
val keyboardHeight = getCurrentKeyboardHeight()
113114
// when keyboard appears values will be (false && true)
114115
// when keyboard disappears values will be (true && false)
115116
val isKeyboardShown = isKeyboardVisible && isKeyboardVisible()
@@ -121,10 +122,17 @@ class KeyboardAnimationCallback(
121122
// `InteractiveKeyboardProvider.isInteractive` detect case when keyboard moves
122123
// because of the gesture
123124
val isMoving = isTransitioning || InteractiveKeyboardProvider.isInteractive
124-
if (isKeyboardShown && !isMoving && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
125-
val keyboardHeight = getCurrentKeyboardHeight()
126-
val duration = DEFAULT_ANIMATION_TIME.toInt()
125+
val isKeyboardFullyVisible = isKeyboardShown && !isMoving
126+
// when keyboard is opened and we trigger a transition from screen A to screen B,
127+
// then this method is getting called and we start dispatching events, and later original
128+
// `onStart`/`onProgress`/`onEnd` emitting their events (since keyboard is closing) and we
129+
// are getting race conditions.
130+
//
131+
// but in general this check is a must because we are detecting keyboard size changes
132+
// in this method
133+
val isKeyboardSizeEqual = this.persistentKeyboardHeight == keyboardHeight
127134

135+
if (isKeyboardFullyVisible && !isKeyboardSizeEqual && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
128136
layoutObserver?.syncUpLayout()
129137
this.emitEvent("KeyboardController::keyboardWillShow", getEventParams(keyboardHeight))
130138
context.dispatchEvent(
@@ -135,7 +143,7 @@ class KeyboardAnimationCallback(
135143
"topKeyboardMoveStart",
136144
keyboardHeight,
137145
1.0,
138-
duration,
146+
DEFAULT_ANIMATION_TIME,
139147
viewTagFocused,
140148
),
141149
)
@@ -152,7 +160,7 @@ class KeyboardAnimationCallback(
152160
"topKeyboardMove",
153161
toValue.toDouble(),
154162
toValue.toDouble() / keyboardHeight,
155-
duration,
163+
DEFAULT_ANIMATION_TIME,
156164
viewTagFocused,
157165
),
158166
)
@@ -167,12 +175,12 @@ class KeyboardAnimationCallback(
167175
"topKeyboardMoveEnd",
168176
keyboardHeight,
169177
1.0,
170-
duration,
178+
DEFAULT_ANIMATION_TIME,
171179
viewTagFocused,
172180
),
173181
)
174182
}
175-
animation.setDuration(DEFAULT_ANIMATION_TIME).startDelay = 0
183+
animation.setDuration(DEFAULT_ANIMATION_TIME.toLong()).startDelay = 0
176184
animation.start()
177185

178186
this.persistentKeyboardHeight = keyboardHeight
@@ -344,6 +352,6 @@ class KeyboardAnimationCallback(
344352
}
345353

346354
companion object {
347-
private const val DEFAULT_ANIMATION_TIME = 250L
355+
private const val DEFAULT_ANIMATION_TIME = 250
348356
}
349357
}

0 commit comments

Comments
 (0)