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-native
core team uses similar approach foronScroll
event fromScrollView
component (also I knew, that it's possible to map events from such callbacks toAnimated.Value
and 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
View
it's easier to change padding of this view. reanimated
allows to interceptview
events using theirsuseEvent
hook and move the event handling into worklet runtime. Thus sending events viaview
allows to make an integration withreanimated
package 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 | ✅ | ❌ |
OverKeyboardView component | ✅ | ❌ |
1 You need to unmount all components that use
useAnimatedKeyboard
to 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-controller
tracks focused input changes (apart of keyboard tracking) and thus brings advanced concepts for keyboard avoidance.
To sum it up:
-
if you are using
useAnimatedKeyboard
and 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-controller
can 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 changesoftInputMode
which should simplify the integration process.