From 133bfd8bf0f9c5d0de34cc9d93ff34d7f4e9ef8c Mon Sep 17 00:00:00 2001 From: Kirill Zyusko Date: Fri, 5 Jan 2024 10:14:55 +0100 Subject: [PATCH] fix: incorrect first frame when keyboard was resized (#316) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📜 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 https://github.com/kirillzyusko/react-native-keyboard-controller/issues/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| |------|------| |