Skip to content

Commit

Permalink
fix: compare size in onApplyWindowInsets (#268)
Browse files Browse the repository at this point in the history
## 📜 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
  • Loading branch information
kirillzyusko committed Nov 13, 2023
1 parent 35570f9 commit 84ac214
Showing 1 changed file with 16 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class KeyboardAnimationCallback(
* - we dispatch `keyboardDidShow` (onEnd).
*/
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
val keyboardHeight = getCurrentKeyboardHeight()
// when keyboard appears values will be (false && true)
// when keyboard disappears values will be (true && false)
val isKeyboardShown = isKeyboardVisible && isKeyboardVisible()
Expand All @@ -121,10 +122,17 @@ class KeyboardAnimationCallback(
// `InteractiveKeyboardProvider.isInteractive` detect case when keyboard moves
// because of the gesture
val isMoving = isTransitioning || InteractiveKeyboardProvider.isInteractive
if (isKeyboardShown && !isMoving && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val keyboardHeight = getCurrentKeyboardHeight()
val duration = DEFAULT_ANIMATION_TIME.toInt()
val isKeyboardFullyVisible = isKeyboardShown && !isMoving
// when keyboard is opened and we trigger a transition from screen A to screen B,
// then this method is getting called and we start dispatching events, and later original
// `onStart`/`onProgress`/`onEnd` emitting their events (since keyboard is closing) and we
// are getting race conditions.
//
// but in general this check is a must because we are detecting keyboard size changes
// in this method
val isKeyboardSizeEqual = this.persistentKeyboardHeight == keyboardHeight

if (isKeyboardFullyVisible && !isKeyboardSizeEqual && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
layoutObserver?.syncUpLayout()
this.emitEvent("KeyboardController::keyboardWillShow", getEventParams(keyboardHeight))
context.dispatchEvent(
Expand All @@ -135,7 +143,7 @@ class KeyboardAnimationCallback(
"topKeyboardMoveStart",
keyboardHeight,
1.0,
duration,
DEFAULT_ANIMATION_TIME,
viewTagFocused,
),
)
Expand All @@ -152,7 +160,7 @@ class KeyboardAnimationCallback(
"topKeyboardMove",
toValue.toDouble(),
toValue.toDouble() / keyboardHeight,
duration,
DEFAULT_ANIMATION_TIME,
viewTagFocused,
),
)
Expand All @@ -167,12 +175,12 @@ class KeyboardAnimationCallback(
"topKeyboardMoveEnd",
keyboardHeight,
1.0,
duration,
DEFAULT_ANIMATION_TIME,
viewTagFocused,
),
)
}
animation.setDuration(DEFAULT_ANIMATION_TIME).startDelay = 0
animation.setDuration(DEFAULT_ANIMATION_TIME.toLong()).startDelay = 0
animation.start()

this.persistentKeyboardHeight = keyboardHeight
Expand Down Expand Up @@ -344,6 +352,6 @@ class KeyboardAnimationCallback(
}

companion object {
private const val DEFAULT_ANIMATION_TIME = 250L
private const val DEFAULT_ANIMATION_TIME = 250
}
}

0 comments on commit 84ac214

Please sign in to comment.