I have a login screen created using react-native.
How can I shift my screen up when the user is typing in the textInput?
Do I listen to the onFocus() event and use css styling to change the style of the view?
I have a login screen created using react-native.
How can I shift my screen up when the user is typing in the textInput?
Do I listen to the onFocus() event and use css styling to change the style of the view?
In 2017 (RN 0.43) there is special component for this: KeyboardAvoidingView
You can use ScrollView to control screen up and down movements. As long as user hasn't focused any TextInput
, you can disable scroll. On focus, just shift up the scrollview using Content Offset prop.
<TextInput
onFocus={this.textInputFocused.bind(this)}
/>
textInputFocused() {
//do your stuff here. scroll screen up
}
Hope it helps!
import {KeyboardAvoidingView} from 'react-native';
<KeyboardAvoidingView style={styles.container} behavior="padding" enabled>
<Text style={{height: 100, marginTop: 30}}> test text before input</Text>
<Text style={{height: 100, marginTop: 30}}> test text before input</Text>
<Text style={{height: 100, marginTop: 30}}> test text before input</Text>
<Text style={{height: 100, marginTop: 30}}> test text before input</Text>
<Text style={{height: 100, marginTop: 30}}> test text before input</Text>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
<Text style={{height: 100, marginTop: 20}}>1 test text after input</Text>
<Text style={{height: 100, marginTop: 20}}>2 test text after input</Text>
<Text style={{height: 100, marginTop: 20}}>3 test text after input</Text>
<Text style={{height: 100, marginTop: 20}}>4 test text after input</Text>
<Text style={{height: 100, marginTop: 20}}>5 test text after input</Text>
</KeyboardAvoidingView>
Run in snack : https://snack.expo.io/H1BE5ZoXV
Night Fury's answer is pretty good, though wouldn't fuss with the ScrollView's contentOffset
, I'd use the ScrollResponder
:
render() {
return (
<ScrollView ref="myScrollView">
<TextInput
ref="myInput"
onFocus={this._scrollToInput.bind(this)}
/>
</ScrollView>
);
}
_scrollToInput {
const scrollResponder = this.refs.myScrollView.getScrollResponder();
const inputHandle = React.findNodeHandle(this.refs.myInput)
scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
inputHandle, // The TextInput node handle
0, // The scroll view's bottom "contentInset" (default 0)
true // Prevent negative scrolling
);
}
See the method definition: scrollResponderScrollNativeHandleToKeyboard
And another solution, working with RN 0.2, this time instead of squashing the content it scrolls.
inputFocused: function(ref) {
this._scroll(ref, 75);
},
inputBlurred: function(ref) {
this._scroll(ref, 0);
},
_scroll: function(ref, offset) {
setTimeout(() => {
var scrollResponder = this.refs.myScrollView.getScrollResponder();
scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
React.findNodeHandle(this.refs[ref]),
offset,
true
);
});
},
...
render: function() {
return <View style={{flex: 1}}>
<ScrollView ref="myScrollView" keyboardDismissMode='interactive' contentContainerStyle={{flex: 1}}>
<TextInput
ref="myInput"
onFocus={this.inputFocused.bind(this, 'myInput')}
onBlur={this.inputBlurred.bind(this, 'myInput')} />
</ScrollView>
</View>
}
It's a crap shoot to get the native keyboard awareness functionality of ScrollView working. For my Android app, it works perfectly in one screen that is nearly identical as the other for which doesn't work. And on iOS, it just doesn't work. This is what's working for me:
import { Keyboard, ScrollView, StyleSheet, View } from 'react-native';
this.state = {
filler: false,
}
componentWillMount() {
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow.bind(this));
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide.bind(this));
}
componentWillUnmount() {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
_keyboardDidShow() {
this.setState({filler: true})
setTimeout(() => this.vertical && this.vertical.scrollToEnd({animated: true}), 0);
}
_keyboardDidHide() {
this.setState({filler: false})
}
...
return (
<ScrollView ref={ref => this.vertical = ref}>
<TextInput/>
{ this.state.filler ? <View style={styles.filler}/> : null }
</ScrollView>
)
styles.filler = {
height: 'Keyboard Height'
}
Note: This might only work if your <TextInput/>
is at the bottom of the screen which it was in my case.