Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect first frame when using KeyboardAvoidingView/KeyboardStickyView+offset and keyboard gets resized #315

Closed
kirillzyusko opened this issue Jan 4, 2024 · 0 comments · Fixed by #316
Assignees
Labels
🤖 android Android specific 🐛 bug Something isn't working 📚 components Anything related to the exported components of this library KeyboardAvoidingView 🧪 Anything related to KeyboardAvoidingView component KeyboardStickyView 🩹 Anything related to KeyboardStickyView component

Comments

@kirillzyusko
Copy link
Owner

Describe the bug

Incorrect first frame when using KeyboardAvoidingView/KeyboardStickyView and keyboard gets resized

Code snippet

Reproducible in example app.

Repo for reproducing

Reproducible in example app.

To Reproduce
Steps to reproduce the behavior:

  1. Go to KeyboardAvoidingView/KeyboardStickyView example screens
  2. Click on TextInput and wait for keyboard to be shown
  3. Resize keyboard (change to emoji input)
  4. Animation starts from a different frame (i. e. view moved down and then animate)

Expected behavior

Animation should start from current/last position.

Screenshots

resize-jump.mp4

Smartphone (please complete the following information):

  • Desktop OS:MacOS 14.1
  • Device: Pixel 7 Pro
  • OS: Android 14
  • RN version: 0.72.4
  • RN architecture: old
  • JS engine: Hermes
  • Library version: 1.10.0

Additional context

It happens because progress becomes 0.7 instead of 1, and because of that we see initial jump.

@kirillzyusko kirillzyusko added 🐛 bug Something isn't working 🤖 android Android specific 📚 components Anything related to the exported components of this library labels Jan 4, 2024
@kirillzyusko kirillzyusko self-assigned this Jan 4, 2024
kirillzyusko added a commit that referenced this issue Jan 5, 2024
## 📜 Description

Fixed incorrect first frame (when keyboard was resized).

## 💡 Motivation and Context

If we use `progress` directly for interpolation we may encounter a
situation when animation looks junky.

It happens because first frame is not calculated properly when we
interpolate value.

First of all let's define how `progress` value is calculated across
platforms when keyboard is resized:
- on iOS it'll be always `1` because keyboard changes size immediately;
- on Android prior to Android 11 we'll have intermediate values;
- on Android 11+ we don't have intermediate values, but to make it more
consistent across platforms I added a transition;

So to sum it up: on iOS `progress` is always `1` when keyboard gets
resized. On Android it will change the value, and the calculation
algorithm looks like: take latest keyboard frame and new final frame ->
divide current to new (in this case we always assure that final
`progress` value will be `1`.

However if we do interpolation directly on `progress` value we may
encounter some issues. Let's say keyboard changes size from `0` to `200`
and we do interpolation from `0` to `230` (`+30` to final keyboard
frame). Then keyboard gets resized from `200` to `220`. In this case
we'll interpolate from `0` to `250`. And initial frame will be 200 / 220
* 250 = 227 (but previous value was 220, so we will see a jump from 220
and 227).

To overcome this problem I added `useKeyboardInterpolation` hook. It
fixes this problem by changing interpolation approach. Basically when
keyboard appears/disappears it uses the same approach as
`progress`-based interpolation.

However when it comes to keyboard resizing it detects this moment and
changes interpolation rules: instead of using a provided range it will
use latest interpolated value as the beginning of `inputRange`, so in
our case discussed above new interpolation will be:

```tsx
{
  inputRange: [200, 220]
  outputRange: [230, 250]
}
```

In this case we will not have a jump and animation will be smooth.

Closes
#315

## 📢 Changelog

### JS

- added `useKeyboardInterpolation` hook;
- use `useKeyboardInterpolation` hook in
`KeyboardAvoidingView`/`KeyboardStickyView`;

## 🤔 How Has This Been Tested?

Tested manually on Pixel 7 Pro.

## 📸 Screenshots (if appropriate):

|Before|After|
|------|------|
|<video
src="https://private-user-images.githubusercontent.com/22820318/294164887-081cfd0d-e308-43de-b946-79c47c9fe9a0.mp4">|<video
src="https://github.com/kirillzyusko/react-native-keyboard-controller/assets/22820318/68109c4b-d17c-40a1-876d-a74fad158efe">|
|<video
src="https://github.com/kirillzyusko/react-native-keyboard-controller/assets/22820318/93a783c9-3db2-41c8-9b92-7f307399729e">|<video
src="https://github.com/kirillzyusko/react-native-keyboard-controller/assets/22820318/13bfb5c2-c1bf-47b5-9a84-a7d2ff5cd6a3">|

## 📝 Checklist

- [x] CI successfully passed
@kirillzyusko kirillzyusko added KeyboardAvoidingView 🧪 Anything related to KeyboardAvoidingView component KeyboardStickyView 🩹 Anything related to KeyboardStickyView component labels May 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🤖 android Android specific 🐛 bug Something isn't working 📚 components Anything related to the exported components of this library KeyboardAvoidingView 🧪 Anything related to KeyboardAvoidingView component KeyboardStickyView 🩹 Anything related to KeyboardStickyView component
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant