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

[useAnimatedKeyboard][iOS] Keyboard interpolation #5705

Merged
merged 11 commits into from
Feb 29, 2024

Conversation

piaskowyk
Copy link
Member

@piaskowyk piaskowyk commented Feb 21, 2024

Summary

The useAnimatedKeyboard() hook doesn't sync with the keyboard animation because keyboard animations use CAAnimations that are computed on the window server. This means they have their own timer and presentation layer. The info we get about the actual keyboard height is just an approximation of the real size shown by the window server.

Our hook, on the other hand, uses a DisplayLink timer, which is different from the CAAnimation timer. With this PR, we are adding a function that attempts to better estimate the keyboard position using easing and Bezier curves. While this solution might not be perfect down to the pixel because window server animations aren't entirely straightforward, it's still a big improvement compared to before.

The Bezier curves are based on the measured keyboard height from screen recordings, and then I adjusted the curves to fit them better.

Basic estimation function:
image

Where:

  • x - time progress of animation
  • a1, a2, b1, b2, d1, d3 - curve parameters

Example of curve:

image

Keyboard appearing: https://www.desmos.com/calculator/aw4ocksord
Keyboard hiding: https://www.desmos.com/calculator/6zay2c6jou

Related info: https://forums.developer.apple.com/forums/thread/712762

Comparison

before after
before.mp4
after.mp4

Test plan

code
import React from 'react';
import { Text, StyleSheet, View, ScrollView, TextInput } from 'react-native';
import Animated, { useAnimatedKeyboard, useAnimatedStyle } from 'react-native-reanimated';

export default function EmptyExample() {
  const keyboard = useAnimatedKeyboard();
  const translateStyle = useAnimatedStyle(() => {
    return {
      transform: [{ translateY: -keyboard.height.value }],
    };
  });
  return (
    <View style={styles.container}>
      <ScrollView 
        style={styles.scroll}
        keyboardDismissMode='interactive'
      >
        {new Array(100).fill(null).map((_, i) => <Text key={i}>{i}</Text>)}
      </ScrollView>
      <Animated.View style={translateStyle}>
        <TextInput style={styles.input} />
      </Animated.View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    display: 'flex',
    justifyContent: 'space-between',
  },
  scroll: {
    width: '100%',
  },
  input: {
    height: 100,
    width: '100%',
    backgroundColor: 'green',
    borderWidth: 1,
  },
});

Copy link
Collaborator

@tjzel tjzel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All looks good to me, but I don't really know much about this part of iOS Reanimated. Please make sure that those changes work when you rapidly switch focus between TextInputs.

apple/keyboardObserver/REAKeyboardEventObserver.mm Outdated Show resolved Hide resolved
apple/keyboardObserver/REAKeyboardEventObserver.mm Outdated Show resolved Hide resolved
apple/keyboardObserver/REAKeyboardEventObserver.mm Outdated Show resolved Hide resolved
apple/keyboardObserver/REAKeyboardEventObserver.mm Outdated Show resolved Hide resolved
apple/keyboardObserver/REAKeyboardEventObserver.mm Outdated Show resolved Hide resolved
@piaskowyk
Copy link
Member Author

I can confirm that, the focus switching between two inputs works correctly.

@piaskowyk piaskowyk changed the title iOS keyboard interpolation [useAnimatedKeyboard][iOS] Keyboard interpolation Feb 27, 2024
apple/REATimer.h Outdated Show resolved Hide resolved
apple/REATimer.h Outdated Show resolved Hide resolved
apple/keyboardObserver/REAKeyboardEventObserver.mm Outdated Show resolved Hide resolved
apple/keyboardObserver/REAKeyboardEventObserver.mm Outdated Show resolved Hide resolved
apple/keyboardObserver/REAKeyboardEventObserver.mm Outdated Show resolved Hide resolved
Copy link
Collaborator

@tjzel tjzel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like equation

@piaskowyk piaskowyk added this pull request to the merge queue Feb 29, 2024
Merged via the queue into main with commit 4d02f7e Feb 29, 2024
12 checks passed
@piaskowyk piaskowyk deleted the @piaskowyk/ios-keyboard-interpolation branch February 29, 2024 13:52
@piaskowyk piaskowyk restored the @piaskowyk/ios-keyboard-interpolation branch February 29, 2024 15:42
@piaskowyk piaskowyk deleted the @piaskowyk/ios-keyboard-interpolation branch March 1, 2024 14:02
@RohovDmytro
Copy link

A legend was born.

And then did this pull request.

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants