Imagine simple ScrollView with multiple TextInputs like
<ScrollView style={styles.container}>
<TextInput style={styles.input} />
<TextInput style={styles.input} />
</ScrollView>
When I enter first input, keyboard opens and I can type text. When I want to change to second input I need to twice tap - first type closes keyboard and only second tap opens the keyboard for second input.
One solution is to use keyboardShouldPersistTaps={true}
- switching works fine however then keyboard is not closed at all and the keyboard can cover some of the later inputs (or buttons).
I can also use keyboardDismissMode
however that just close keyboard on drag.
My question is how to combine those two behaviour - into IMHO the best user experience - when I click another input, the focus is changed immediately without reopening keyboard and when I tap somewhere else the keyboard is closed?
I am using RN0.22 and sample application is available at https://rnplay.org/apps/kagpGw
UPDATE - This problem might have been solved in RN 0.40 - see https://github.com/facebook/react-native/commit/552c60192172f6ec503181c060c08bbc5cbcc5a4
I solved my problem with this code
<ScrollView
keyboardDismissMode='on-drag'
keyboardShouldPersistTaps={true}
>
In the new react-native versions you can persist the on scrollview click event like below:
<ScrollView
keyboardShouldPersistTaps='always'
keyboardDismissMode={'interactive'}></ScrollView>
The main trick is keyboardShouldPersistTaps='always'
This SO answer isn't exactly what you're asking for, but will auto-slide the window out from behind the keyboard when a TextInput has focus; resolving your keyboard can cover some of the later inputs (or buttons) issue.
At the end I found solution that is not optimal (from coding perspective) but works from user perspective. I made small component that can be used instead of ScrollView
:
export class InputScrollView extends React.Component {
constructor(props, ctx) {
super(props, ctx);
this.handleCapture = this.handleCapture.bind(this);
}
render() {
return (
<ScrollView keyboardShouldPersistTaps={true} keyboardDismissMode='on-drag'>
<View onStartShouldSetResponderCapture={this.handleCapture}>
{this.props.children}
</View>
</ScrollView>
);
}
handleCapture(e) {
const focusField = TextInputState.currentlyFocusedField();
const target = e.nativeEvent.target;
if (focusField != null && target != focusField){
const inputs = this.props.inputs;
if (inputs && inputs.indexOf(target) === -1) {
dismissKeyboard();
}
}
}
}
InputScrollView.propTypes = {
inputs : React.PropTypes.array,
}
The only drawback is that I need to collect node handles (as returned by React.findNodeHandle
) of all text inputs "manually" and pass it to the component as an array.
By looking at https://facebook.github.io/react-native/docs/scrollview.html#keyboarddismissmode I find out a method that can do these:
The code is as follows:
<ScrollView
keyboardDismissMode="none"
keyboardShouldPersistTaps="handled"
>
{content}
</ScrollView>
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