首页 文章

React Native:如何在按下“下一个”键盘按钮后选择下一个TextInput?

提问于
浏览
106

我定义了两个TextInput字段,如下所示:

<TextInput 
   style = {styles.titleInput}
   returnKeyType = {"next"}
   autoFocus = {true}
   placeholder = "Title" />
<TextInput
   style = {styles.descriptionInput}          
   multiline = {true}
   maxLength = {200}
   placeholder = "Description" />

但是在按下键盘上的“下一步”按钮后,我的react-native应用程序没有跳转到第二个TextInput字段 . 我怎样才能做到这一点?

谢谢!

15 回答

  • 1

    当前一个 TextInputonSubmitEditing 被触发时,设置第二个 TextInput 焦点 .

    试试这个

    • 将参考添加到 second TextInput
      ref={(input) => { this.secondTextInput = input; }}

    • 将焦点函数绑定到 first TextInput 的onSubmitEditing事件 .
      onSubmitEditing={() => { this.secondTextInput.focus(); }}

    • 切记将blurOnSubmit设置为false,以防止键盘闪烁 .
      blurOnSubmit={false}

    完成后,它应该是这样的 .

    <TextInput
        placeholder = "FirstTextInput"
        returnKeyType = { "next" }
        onSubmitEditing={() => { this.secondTextInput.focus(); }}
        blurOnSubmit={false}
    />
    
    <TextInput
        ref={(input) => { this.secondTextInput = input; }}
        placeholder = "secondTextInput"
    />
    
  • 16

    你可以这样做 without using refs . 这种方法是首选,因为refs可以导致 fragile code . React docs建议尽可能找到其他解决方案:

    如果您还没有使用React编写多个应用程序,那么您的第一个倾向通常是尝试使用refs在您的应用程序中“让事情发生” . 如果是这种情况,请花一点时间,更关键地考虑组件层次结构中应该拥有状态的位置 . 通常,很明显,“拥有”该状态的适当位置在层次结构中处于更高级别 . 在那里放置状态通常消除了使用refs“让事情发生”的任何愿望 - 相反,数据流通常会实现你的目标 .

    相反,我们将使用状态变量来聚焦第二个输入字段 .

    • 添加一个我们将作为道具传递给 DescriptionInput 的状态变量:
    initialState() {
      return {
        focusDescriptionInput: false,
      };
    }
    
    • 定义将此状态变量设置为true的处理程序方法:
    handleTitleInputSubmit() {
      this.setState(focusDescriptionInput: true);
    }
    
    • TitleInput 上提交/点击进入/下一步后,我们将调用 handleTitleInputSubmit . 这会将 focusDescriptionInput 设置为true .
    <TextInput 
       style = {styles.titleInput}
       returnKeyType = {"next"}
       autoFocus = {true}
       placeholder = "Title" 
       onSubmitEditing={this.handleTitleInputSubmit}
    />
    
    • DescriptionInputfocus prop设置为我们的 focusDescriptionInput 状态变量 . 因此,当 focusDescriptionInput 更改(在步骤3中)时, DescriptionInput 将使用 focus={true} 重新渲染 .
    <TextInput
       style = {styles.descriptionInput}          
       multiline = {true}
       maxLength = {200}
       placeholder = "Description" 
       focus={this.state.focusDescriptionInput}
    />
    

    这是避免使用refs的好方法,因为refs会导致更脆弱的代码:)

    编辑:h / t @LaneRettig指出你需要用一些添加的道具和方法包装React Native TextInput来让它响应 focus

    // Props:
        static propTypes = { 
            focus: PropTypes.bool,
        } 
    
        static defaultProps = { 
            focus: false,
        } 
    
        // Methods:
        focus() {
            this._component.focus(); 
        } 
    
        componentWillReceiveProps(nextProps) {
            const {focus} = nextProps; 
    
            focus && this.focus(); 
        }
    
  • 7

    从React Native 0.36开始,不再支持在文本输入节点上调用 focus() (如其他几个答案所示) . 相反,您可以使用React Native中的 TextInputState 模块 . 我创建了以下帮助程序模块以使其更容易:

    // TextInputManager
    //
    // Provides helper functions for managing the focus state of text
    // inputs. This is a hack! You are supposed to be able to call
    // "focus()" directly on TextInput nodes, but that doesn't seem
    // to be working as of ReactNative 0.36
    //
    import { findNodeHandle } from 'react-native'
    import TextInputState from 'react-native/lib/TextInputState'
    
    
    export function focusTextInput(node) {
      try {
        TextInputState.focusTextInput(findNodeHandle(node))
      } catch(e) {
        console.log("Couldn't focus text input: ", e.message)
      }
    }
    

    然后,您可以在 TextInput 的"ref"上调用 focusTextInput 函数 . 例如:

    ...
    <TextInput onSubmit={() => focusTextInput(this.refs.inputB)} />
    <TextInput ref="inputB" />
    ...
    
  • 0

    我创建了一个小型库来执行此操作,除了替换包装视图和导入TextInput之外,不需要更改代码:

    import { Form, TextInput } from 'react-native-autofocus'
    
    export default () => (
      <Form>
        <TextInput placeholder="test" />
        <TextInput placeholder="test 2" />
      </Form>
    )
    

    https://github.com/zackify/react-native-autofocus

    这里详细解释:https://zach.codes/autofocus-inputs-in-react-native/

  • 1

    使用react-native 0.45.1我在按用户名TextInput上的返回键后尝试将焦点设置为密码TextInput时也遇到了问题 .

    在这里尝试了大多数评价最高的解决方案后,我在github上找到了满足我需求的解决方案:https://github.com/shoutem/ui/issues/44#issuecomment-290724642

    把它们加起来:

    import React, { Component } from 'react';
    import { TextInput as RNTextInput } from 'react-native';
    
    export default class TextInput extends Component {
        render() {
            const { props } = this;
    
            return (
                <RNTextInput
                    {...props}
                    ref={(input) => props.inputRef && props.inputRef(input)}
                />
            );
        }
    }
    

    然后我像这样使用它:

    import React, {Component} from 'react';
    import {
        View,
    } from 'react-native';
    import TextInput from "../../components/TextInput";
    
    class Login extends Component {
        constructor(props) {
            super(props);
            this.passTextInput = null
        }
    
        render() {
            return (
                <View style={{flex:1}}>
                    <TextInput
                        style={{flex:1}}
                        placeholder="Username"
                        onSubmitEditing={(event) => {
                            this.passTextInput.focus()
                        }}
                    />
    
                    <TextInput
                        style={{flex:1}}
                        placeholder="Password"
                        inputRef={(input) => {
                            this.passTextInput = input
                        }}
                    />
                </View>
            )
        }
    }
    
  • 182

    如果您正好像我一样使用tcomb-form-native,那么您也可以这样做 . 这是诀窍:不是直接设置 TextInput 的道具,而是通过 options 来实现 . 您可以将表单的字段称为:

    this.refs.form.getComponent('password').refs.input.focus()
    

    所以最终产品看起来像这样:

    var t = require('tcomb-form-native');
    var Form = t.form.Form;
    
    var MyForm = t.struct({
      field1:     t.String,
      field2:     t.String,
    });
    
    var MyComponent = React.createClass({
    
      _getFormOptions () {
        return {
          fields: {
            field1: {
              returnKeyType: 'next',
              onSubmitEditing: () => {this.refs.form.getComponent('field2').refs.input.focus()},
            },
          },
        };
      },
    
      render () {
    
        var formOptions = this._getFormOptions();
    
        return (
          <View style={styles.container}>
            <Form ref="form" type={MyForm} options={formOptions}/>
          </View>
        );
      },
    });
    

    (感谢remcoanker在这里发布这个想法:https://github.com/gcanti/tcomb-form-native/issues/96

  • 11

    对我来说,RN 0.50.3可以用这种方式:

    <TextInput 
      autoFocus={true} 
      onSubmitEditing={() => {this.PasswordInputRef._root.focus()}} 
    />
    
    <TextInput ref={input => {this.PasswordInputRef = input}} />
    

    你必须看到这个.PasswordInputRef . _root .focus()

  • 2

    在React Native的GitHub问题上尝试这个解决方案 .

    https://github.com/facebook/react-native/pull/2149#issuecomment-129262565

    您需要为TextInput组件使用ref prop .
    然后你需要创建一个在onSubmitEditing prop上调用的函数,该函数将焦点移动到第二个TextInput引用 .

    var InputScreen = React.createClass({
        _focusNextField(nextField) {
            this.refs[nextField].focus()
        },
    
        render: function() {
            return (
                <View style={styles.container}>
                    <TextInput
                        ref='1'
                        style={styles.input}
                        placeholder='Normal'
                        returnKeyType='next'
                        blurOnSubmit={false}
                        onSubmitEditing={() => this._focusNextField('2')}
                    />
                    <TextInput
                        ref='2'
                        style={styles.input}
                        keyboardType='email-address'
                        placeholder='Email Address'
                        returnKeyType='next'
                        blurOnSubmit={false}
                        onSubmitEditing={() => this._focusNextField('3')}
                    />
                    <TextInput
                        ref='3'
                        style={styles.input}
                        keyboardType='url'
                        placeholder='URL'
                        returnKeyType='next'
                        blurOnSubmit={false}
                        onSubmitEditing={() => this._focusNextField('4')}
                    />
                    <TextInput
                        ref='4'
                        style={styles.input}
                        keyboardType='numeric'
                        placeholder='Numeric'
                        blurOnSubmit={false}
                        onSubmitEditing={() => this._focusNextField('5')}
                    />
                    <TextInput
                        ref='5'
                        style={styles.input}
                        keyboardType='numbers-and-punctuation'
                        placeholder='Numbers & Punctuation'
                        returnKeyType='done'
                    />
                </View>
            );
        }
    });
    
  • 2

    使用回调引用而不是legacy字符串引用:

    <TextInput
        style = {styles.titleInput}
        returnKeyType = {"next"}
        autoFocus = {true}
        placeholder = "Title"
        onSubmitEditing={() => {this.nextInput.focus()}}
    />
    <TextInput
        style = {styles.descriptionInput}  
        multiline = {true}
        maxLength = {200}
        placeholder = "Description"
        ref={nextInput => this.nextInput = nextInput}
    />
    
  • 42

    如果您的 TextInput 在另一个组件中,则可以使用已接受的解决方案,您需要 refref 到父容器的引用 .

    // MyComponent
    render() {
        <View>
            <TextInput ref={(r) => this.props.onRef(r)} { ...this.props }/>
        </View>
    }
    
    // MyView
    render() {
        <MyComponent onSubmitEditing={(evt) => this.myField2.focus()}/>
        <MyComponent onRef={(r) => this.myField2 = r}/>
    }
    
  • 3

    这是我实现它的方式 . 下面的示例使用了React 16.3中引入的React.createRef()API .

    class Test extends React.Component {
      constructor(props) {
        super(props);
        this.secondTextInputRef = React.createRef();
      }
    
      render() {
        return(
            <View>
                <TextInput
                    placeholder = "FirstTextInput"
                    returnKeyType="next"
                    onSubmitEditing={() => { this.secondTextInputRef.current.focus(); }}
                />
                <TextInput
                    ref={this.secondTextInputRef}
                    placeholder = "secondTextInput"
                />
            </View>
        );
      }
    }
    

    我想这会对你有所帮助 .

  • 7

    有一种方法可以在 TextInput 中捕获 tabs . 这是hacky,但比nothing更好 .

    定义一个 onChangeText 处理程序将新输入值与旧输入值进行比较,检查 \t . 如果找到一个,请按@boredgames所示前进该字段

    假设变量 username 包含用户名的值,并且 setUsername 调度在商店中更改它的操作(组件状态,redux存储等),请执行以下操作:

    function tabGuard (newValue, oldValue, callback, nextCallback) {
      if (newValue.indexOf('\t') >= 0 && oldValue.indexOf('\t') === -1) {
        callback(oldValue)
        nextCallback()
      } else {
        callback(newValue)
      }
    }
    
    class LoginScene {
      focusNextField = (nextField) => {
        this.refs[nextField].focus()
      }
    
      focusOnPassword = () => {
        this.focusNextField('password')
      }
    
      handleUsernameChange = (newValue) => {
        const { username } = this.props            // or from wherever
        const { setUsername } = this.props.actions // or from wherever
    
        tabGuard(newValue, username, setUsername, this.focusOnPassword)
      }
    
      render () {
        const { username } = this.props
    
        return (
          <TextInput ref='username'
                     placeholder='Username'
                     autoCapitalize='none'
                     autoCorrect={false}
                     autoFocus
                     keyboardType='email-address'
                     onChangeText={handleUsernameChange}
                     blurOnSubmit={false}
                     onSubmitEditing={focusOnPassword}
                     value={username} />
        )
      }
    }
    
  • 3

    在您的组件中:

    constructor(props) {
            super(props);
            this.focusNextField = this
                .focusNextField
                .bind(this);
            // to store our input refs
            this.inputs = {};
        }
        focusNextField(id) {
            console.log("focus next input: " + id);
            this
                .inputs[id]
                ._root
                .focus();
        }
    

    注意:我使用 ._root ,因为它是NativeBase'Library' Input中的TextInput引用

    并在你的文字输入这样

    <TextInput
             onSubmitEditing={() => {
                              this.focusNextField('two');
                              }}
             returnKeyType="next"
             blurOnSubmit={false}/>
    
    
    <TextInput      
             ref={input => {
                  this.inputs['two'] = input;
                            }}/>
    
  • 1

    我的场景是 < CustomBoladonesTextInput /> 包裹RN < TextInput /> .

    我解决了这个问题如下:

    我的表格如下:

    <CustomBoladonesTextInput 
          onSubmitEditing={() => this.customInput2.refs.innerTextInput2.focus()}
          returnKeyType="next"
          ... />
    
      <CustomBoladonesTextInput 
           ref={ref => this.customInput2 = ref}
           refInner="innerTextInput2"
           ... />
    

    在CustomBoladonesTextInput的组件定义中,我将refField传递给内部ref prop,如下所示:

    export default class CustomBoladonesTextInput extends React.Component {
          render() {        
             return (< TextInput ref={this.props.refInner} ... />);     
          } 
       }
    

    瞧 . 一切都恢复正常 . 希望这可以帮助

  • 23

    这里是具有:focus属性的输入组件的试剂解决方案 .

    只要此prop为true,就会聚焦该字段,只要这是假的,就不会有焦点 .

    不幸的是这个组件需要有一个:ref定义,我找不到另一种方法来调用.focus() . 我对建议很满意 .

    (defn focusable-input [init-attrs]
      (r/create-class
        {:display-name "focusable-input"
         :component-will-receive-props
           (fn [this new-argv]
             (let [ref-c (aget this "refs" (:ref init-attrs))
                   focus (:focus (ru/extract-props new-argv))
                   is-focused (.isFocused ref-c)]
               (if focus
                 (when-not is-focused (.focus ref-c))
                 (when is-focused (.blur ref-c)))))
         :reagent-render
           (fn [attrs]
             (let [init-focus (:focus init-attrs)
                   auto-focus (or (:auto-focus attrs) init-focus)
                   attrs (assoc attrs :auto-focus auto-focus)]
               [input attrs]))}))
    

    https://gist.github.com/Knotschi/6f97efe89681ac149113ddec4c396cc5

相关问题