Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native requires two taps to change input focus when within scrollview

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

like image 438
sodik Avatar asked Apr 07 '16 12:04

sodik


5 Answers

I solved my problem with this code

<ScrollView
   keyboardDismissMode='on-drag'
   keyboardShouldPersistTaps={true}
>
like image 128
Gustavo Rozolin Avatar answered Nov 01 '22 15:11

Gustavo Rozolin


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'

like image 26
Julfikar Avatar answered Oct 05 '22 11:10

Julfikar


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.

like image 3
Josh Buchea Avatar answered Nov 01 '22 15:11

Josh Buchea


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.

like image 3
sodik Avatar answered Nov 01 '22 15:11

sodik


By looking at https://facebook.github.io/react-native/docs/scrollview.html#keyboarddismissmode I find out a method that can do these:

  1. After doing input in TextInput1, if you click Input2, the keyboard persists.
  2. If you click somewhere empty, the keyboard will automatically disappear.

The code is as follows:

<ScrollView
  keyboardDismissMode="none"
  keyboardShouldPersistTaps="handled"
>
  {content}
</ScrollView>
like image 2
ch271828n Avatar answered Nov 01 '22 13:11

ch271828n