Architecture
This library requires to wrap an app with KeyboardProvider component. It's needed because it stores animated values in context.
Process overview
Library exposes KeyboardControllerView with onKeyboardMove method. This method is fired when keyboard frame is changed. KeyboardProvider automatically maps these events to Animated.Value and Reanimated.SharedValue and stores it in context.
Under the hood KeyboardControllerView is a simple View with one additional onKeyboardMove callback method, so it inherits all props from plain View, such as style, etc.
Thus we have a single source of truth about keyboard position. Since values are stored in context we can use it in any component where we need them. Moreover, we can consume context values in class components as well as in hooks.
Design principles
The library was designed to use a context as a global store for animated values and have a single Provider across the app. As of now it may be not very obvious, why it was needed to have a single source of data flow, but in future it may significantly simplify the process of the integration new features.
Why custom KeyboardControllerView is needed?
Initially I had a choice which approach to use in order to send events about keyboard frames: EventEmitters vs View with callbacks. I decided to use View with callbacks because of several reasons:
react-nativecore team uses similar approach foronScrollevent fromScrollViewcomponent (also I knew, that it's possible to map events from such callbacks toAnimated.Valueand thus reduce bridge usage);- to track keyboard frames on Android we need to enter to edge-to-edge mode and it changes view paddings. Since it's managed through
Viewit's easier to change padding of this view. reanimatedallows to interceptviewevents using theirsuseEventhook and move the event handling into worklet runtime. Thus sending events viaviewallows to make an integration withreanimatedpackage and handle events/animate everything directly on the UI thread.
What is the difference between useAnimatedKeyboard from react-native-reanimated and this library?
react-native-keyboard-controller uses its own implementation for keyboard handling and leverages react-native-reanimated solely for performing UI thread updates using SharedValue (the library doesn't simply re-export useAnimatedKeyboard hook in any kind of form).
While both useAnimatedKeyboard from react-native-reanimated and this library aims to provide the same functionality, there are some differences between them. Below you can find a comparison of the two libraries:
react-native-keyboard-controller | react-native-reanimated | |
|---|---|---|
| Map keyboard movement to animated value | ✅ | ✅ |
| Synchronously update keyboard position on UI thread | ✅ | ✅ |
Dynamically switch softInputMode | ✅ | ❌ |
| An ability to turn functionality on demand | ✅ | 🟠 1 |
| Android interactive keyboard support | ✅ | ❌ |
| iOS interactive keyboard support | ✅ | ✅ |
| Has pre-built components | ✅ | ❌ |
Works in Modal on Android | ✅ | 🟠 2 |
| Is ready-to-use library for keyboard avoidance3 | ✅ | ❌ |
KeyboardToolbar component | ✅ | ❌ |
1 You need to unmount all components that use
useAnimatedKeyboardto disable module functionality, which can be hard to achieve if you are using deep Stack-navigators.
2 Planned to be added in the future
3 The
react-native-keyboard-controllertracks focused input changes (apart of keyboard tracking) and thus brings advanced concepts for keyboard avoidance.
To sum it up:
-
if you are using
useAnimatedKeyboardand you are satisfied with it, then there is no sense to switch toreact-native-keyboard-controller; -
if you are planning to add advanced keyboard handling into large existing project, then
react-native-keyboard-controllercan be a better choice, since it has drop-in replacement components (KeyboardAvoidingView,KeyboardAwareScrollView, etc.), you can toggle the functionality dynamically on per screen basic, you can dynamically changesoftInputModewhich should simplify the integration process.