【问题标题】:React Native requires two taps to change input focus when within scrollview在滚动视图中,React Native 需要两次点击来更改输入焦点
【发布时间】:2016-07-28 08:32:52
【问题描述】:

想象一下带有多个 TextInput 的简单 ScrollView,例如

  <ScrollView style={styles.container}>
    <TextInput style={styles.input} />
    <TextInput style={styles.input} />
  </ScrollView>

当我输入第一个输入时,键盘会打开,我可以输入文本。当我想更改为第二个输入时,我需要点击两次 - 第一次关闭键盘,只有第二次点击打开键盘以进行第二次输入。

一种解决方案是使用keyboardShouldPersistTaps={true} - 切换工作正常,但是键盘根本没有关闭,键盘可以覆盖一些后来的输入(或按钮)。 我也可以使用keyboardDismissMode,但是只需在拖动时关闭键盘。

我的问题是如何将这两种行为结合起来 - 恕我直言,最好的用户体验 - 当我点击另一个输入时,焦点会立即更改,而无需重新打开键盘,当我点击其他地方时,键盘会关闭?

我正在使用 RN0.22,示例应用程序可在 https://rnplay.org/apps/kagpGw 获得

更新 - 这个问题可能已在 RN 0.40 中解决 - 请参阅 https://github.com/facebook/react-native/commit/552c60192172f6ec503181c060c08bbc5cbcc5a4

【问题讨论】:

    标签: reactjs keyboard react-native


    【解决方案1】:

    这个SO answer 不完全符合您的要求,但是当 TextInput 获得焦点时,它会自动从键盘后面滑出窗口;解决您的键盘可以解决一些后来的输入(或按钮)问题。

    【讨论】:

    • 谢谢。如果您单击输入,该答案会有所帮助,然后一旦打开,它就会被键盘覆盖。但是,如果已经涵盖了第二个输入(或按钮),则不会对您有所帮助-因为此技巧只会将第一个点击的输入滚动到“视图”中,但不能保证其他组件。
    【解决方案2】:

    最后,我发现不是最优的解决方案(从编码的角度来看),但从用户的角度来看是可行的。我制作了可以用来代替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,
    }
    

    唯一的缺点是我需要“手动”收集所有文本输入的节点句柄(由React.findNodeHandle 返回)并将其作为数组传递给组件。

    【讨论】:

    • 您能解释一下TextInputState 来自哪里吗?哪个包?
    • 它带有 RN - 请参阅 github.com/facebook/react-native/… - 我确实像 import TextInputState from 'TextInputState'; 一样导入了它
    • 谢谢,我去看看! @sodik
    【解决方案3】:

    我用这段代码解决了我的问题

    <ScrollView
       keyboardDismissMode='on-drag'
       keyboardShouldPersistTaps={true}
    >
    

    【讨论】:

    • 问题是当您在输入之外点击时键盘没有关闭。
    • @sodik 看看我的回答 :)
    【解决方案4】:

    我已更新上述答案,因为不推荐使用 keyboardShouldPersistTaps={true},现在使用了 keyboardShouldPersistTaps='always'

    export class InputScrollView extends React.Component {
    
      constructor(props, ctx) {
          super(props, ctx);
          this.handleCapture = this.handleCapture.bind(this);
      }
    
      render() {
        return (
          <ScrollView keyboardShouldPersistTaps='always' 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,
    }
    

    【讨论】:

      【解决方案5】:

      通过查看https://facebook.github.io/react-native/docs/scrollview.html#keyboarddismissmode,我发现了一种可以做到这些的方法:

      1. 在 TextInput1 中输入后,如果单击 Input2,键盘仍然存在。
      2. 如果单击空白处,键盘将自动消失。

      代码如下:

      <ScrollView
        keyboardDismissMode="none"
        keyboardShouldPersistTaps="handled"
      >
        {content}
      </ScrollView>
      

      【讨论】:

        【解决方案6】:

        在新的 react-native 版本中,您可以保持滚动视图单击事件,如下所示:

        <ScrollView
              keyboardShouldPersistTaps='always'
              keyboardDismissMode={'interactive'}></ScrollView>
        

        主要技巧是keyboardShouldPersistTaps='always'

        【讨论】:

          【解决方案7】:

          如果 keyboardShouldPersistTaps="always" 不适合您,请检查您的按钮及其执行的操作。
          无论keyboardShouldPersistTaps 值如何,拥有类似于以下代码的内容可能会导致两次点击问题:

          const submit = () => {
            const _valid = some_validator();
            setValid(_valid);
          
            if (valid) {
              // expected action
              // may not fire on first press due to the state update call above
              api.someAction();
            } else {
              // some error thing
            }
          };
          

          相反,您可以使用 useEffect 来分隔按钮状态调用和生成的操作,以便单击事件具有单一目的

          useEffect(()=>{
            if(valid) {
              // expected action
              api.someAction();
            }
          }, [valid])
          

          【讨论】:

            猜你喜欢
            • 2019-10-25
            • 1970-01-01
            • 1970-01-01
            • 2017-05-12
            • 1970-01-01
            • 1970-01-01
            • 2019-07-04
            • 2018-04-09
            • 2022-07-05
            相关资源
            最近更新 更多