Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

KeyboardAvoidingView - Reset height when Keyboard is hidden

Tags:

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.

Screenshot

like image 416
mxmtsk Avatar asked Jan 12 '17 15:01

mxmtsk


People also ask

How do I stop keyboard pushing layout up in Android React Native?

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.

How do you make your React Native app respond gracefully when the keyboard pops up?

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.

How do you move a view up when keyboard appears React Native?

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).

How KeyboardAvoidingView works?

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.


2 Answers

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

Update

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.

like image 101
Samer Murad Avatar answered Sep 22 '22 09:09

Samer Murad


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}> 
like image 31
Nisarg Thakkar Avatar answered Sep 18 '22 09:09

Nisarg Thakkar