I'm using React Natives KeyboardAvoidingView
to set the height of my View
when the Keyboard is shown. But when I close the the keyboard in the app, the height of the View is not changed back to it's original value.
<KeyboardAvoidingView behavior="height" style={styles.step}> <View style={styles.stepHeader}> // my content </View> </KeyboardAvoidingView>
The View with the red outline did take up the whole space before I opened and closed the keyboard.
Use android:windowSoftInputMode="adjustResize". KeyboardAvoidingView and other keyboard-related components don't work quite well if you have "adjustPan" set for your android:windowSoftInputMode in AndroidManifest. xml . Instead, you should use "adjustResize" and have a wonderful life.
The first thing you have to do is replace the container View with the KeyboardAvoidingView and then add a behavior prop to it. If you look at the documentation you'll see that it accepts 3 different values — height, padding, position. I've found that padding works in the most predictable manner.
android:windowSoftInputMode="adjustPan" will make the Main activity view PAN move (i.e. be translated) outside of the screen! Use "adjustResize" if you want your components to resize (e.g. put one <View> with style={{flex:1}} and it will be the one that resizes when the keyboard is visible).
KeyboardAvoidingView is a React Native built-in component with full JS implementation. It relies on RN's keyboard events ( keyboardWillChangeFrame on iOS & keyboardDidHide/Show on Android) and, based on provided behavior prop, applies additional padding, translation, or changes container's height.
A more detailed explanation on Nisarg's answer.
Create a key for the KeyboardAvoidingView
in the constructor
constructor(props) { this.state = { keyboardAvoidingViewKey: 'keyboardAvoidingViewKey', } }
add listener on the keyboard's will/did hide (and remove it in the willUnmount)
import { KeyboardAvoidingView, Keyboard, Platform } from 'react-native' componentDidMount() { // using keyboardWillHide is better but it does not work for android this.keyboardHideListener = Keyboard.addListener(Platform.OS === 'android' ? 'keyboardDidHide': 'keyboardWillHide', this.keyboardHideListener.bind(this)); } componentWillUnmount() { this.keyboardHideListener.remove() }
update the keyboardAvoidingViewKey
in the keyboardHideListener
function, should be a new value each time (I used a timestamp) and use this key when rendering the KeyboardAvoidingView
element.
keyboardHideListener() { this.setState({ keyboardAvoidingViewKey:'keyboardAvoidingViewKey' + new Date().getTime() }); } render() { let { keyboardAvoidingViewKey } = this.state return ( <KeyboardAvoidingView behavior={'height'} key={keyboardAvoidingViewKey} style={...}> ... </KeyboardAvoidingView> ) }
Note: Keep in mind that this will recreate the elements inside the KeyboardAvoidingView
(i.e: will call their constructor
function, I'm not quite sure why, I'll update the answer after deeper investigation), so you'll have to keep track of any state/prop values that might be overwritten
After a much deeper investigation, I now know why the views are recreated once you change the key. In order to truly understand why it happens, one must be familiar with how react-native dispatches the render commands to the native side, this particular explanation is pretty long, if it interests you, you can read my answer here. In short, react-native uses Reactjs to diff the changes that should be rendered, these diffs are then sent as commands to a component named UIManager
, which sends imperative commands that translate into a layout tree, which changes the layout based on the diff commands. Once you set a key on a component, reactjs uses this key to identify changes to said component, if this key changes, reactjs identifies the component as a completely new one, which in return sends the initial command to create said component, making all it's children to be created from scratch because there are identified as new elements in a new layout tree, deleting the old tree and creating a new one instead of just adjusting the diffs
If you would like, you can actually spy on these dispatched messages by adding the following code to your App.js
file:
import MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue' const spyFunction = (msg) => { console.log(msg); }; MessageQueue.spy(spyFunction);
If you do that, you'll notice in the logs that each time the key changes, the command that is dispatched in return is createViews
, which like stated above creates all the elements that are nested under said component.
Please give key to KeyboardAvoidingView and change when keyboard open and close so it will render and take height
<KeyboardAvoidingView behavior="height" style={styles.step} key={values}>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With