UPDATE: Try to use this lib instead:
https://github.com/kirillzyusko/react-native-keyboard-controller
It solved a lot of our problems.
This is what worked for us
- We need to create a hook that will tell us that keyboard will hide (we will need it later):
import { useEffect, useState } from 'react';
import { Keyboard } from 'react-native';
export const useKeyboardVisible = () => {
const [isKeyboardWillHide, setKeyboardWillHide] = useState(false);
useEffect(() => {
const keyboardWillHideListener = Keyboard.addListener('keyboardWillHide', () => {
setKeyboardWillHide(true);
});
return () => {
keyboardWillHideListener.remove();
};
}, []);
return { isKeyboardWillHide };
};
- Next we will need to create a hook that will return us animated
marginBottom
styles (for smooth layout change):
- establish that keyboard is already visible using
Keyboard.isVisible();
;
- get keyboard height using
Keyboard.metrics()
;
- if keyboard is visible -> set
marginBottom
= keyboard height
import { Keyboard } from 'react-native';
import { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
const useKeyboardAlreadyVisibleMarginFix = () => {
const { isKeyboardWillHide } = useKeyboardVisible();
const marginBottom = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => {
return {
marginBottom: marginBottom.value
? marginBottom.value
: withTiming(0, {
duration: 300,
}),
};
}, []);
useEffect(() => {
const isVisible = Keyboard.isVisible();
const metrics = Keyboard.metrics();
if (isVisible) {
marginBottom.value = metrics?.height ?? 0;
}
if (isKeyboardWillHide) {
marginBottom.value = 0;
}
return () => {
marginBottom.value = 0;
};
}, [isKeyboardWillHide, marginBottom]);
return { animatedStyle };
};
- Use `Animated.View for making layout animation more user-friendly:
import { Keyboard, KeyboardAvoidingView, Platform } from 'react-native';
import { useHeaderHeight } from '@react-navigation/elements';
import Animated from 'react-native-reanimated';
// ...
const height = useHeaderHeight();
const { animatedStyle } = useKeyboardAlreadyVisibleMarginFix();
if (Platform.OS === 'ios') {
return (
<KeyboardAvoidingView behavior="padding" style={{flex: 1}} keyboardVerticalOffset={height}>
<Animated.View style={[{ flex: 1 }, animatedStyle]}>{children}</Animated.View>
</KeyboardAvoidingView>
);
}