React Native:如何在按下" next"之后选择下一个TextInput。键盘按钮?

时间:2015-09-23 20:17:51

标签: ios react-native

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

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

但在按下&#34; next&#34;我的键盘上的按钮,我的本机应用程序没有跳转到第二个TextInput字段。我怎样才能做到这一点?

谢谢!

23 个答案:

答案 0 :(得分:217)

在触发上一个TextInput的{​​{1}}时设置第二个TextInput焦点。

试试这个

  1. 将参考添加到第二个TextInput
    onSubmitEditing

  2. 将焦点功能绑定到第一个TextInput 的onSubmitEditing事件。
    ref={(input) => { this.secondTextInput = input; }}

  3. 请记住将blurOnSubmit设置为false,以防止键盘闪烁 onSubmitEditing={() => { this.secondTextInput.focus(); }}

  4.   

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

    blurOnSubmit={false}

答案 1 :(得分:47)

您可以执行此操作,而不使用参考。这种方法是首选,因为refs可能导致脆弱的代码React docs建议尽可能找到其他解决方案:

  

如果您还没有使用React编写多个应用程序,那么您的第一个应用程序   倾向通常是尝试使用refs来制造东西   发生&#34;在你的应用程序中如果是这种情况,请花一点时间思考更多   批判性的关于组件中应该拥有哪个州   层次结构。通常情况下,很明显,适当的地方是拥有&#34;那   state在层次结构中处于更高级别。把国家放在那里   通常会消除任何使用refs以使事情发生的愿望。 -   相反,数据流通常会实现您的目标。

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

  1. 添加一个我们将作为道具传递给DescriptionInput的状态变量:

    initialState() {
      return {
        focusDescriptionInput: false,
      };
    }
    
  2. 定义一个将此状态变量设置为true的处理程序方法:

    handleTitleInputSubmit() {
      this.setState(focusDescriptionInput: true);
    }
    
  3. TitleInput上提交/点击进入/下一步后,我们会致电handleTitleInputSubmit。这会将focusDescriptionInput设置为true。

    <TextInput 
       style = {styles.titleInput}
       returnKeyType = {"next"}
       autoFocus = {true}
       placeholder = "Title" 
       onSubmitEditing={this.handleTitleInputSubmit}
    />
    
  4. DescriptionInput&#39; focus道具设置为我们的focusDescriptionInput状态变量。因此,当focusDescriptionInput更改时(在步骤3中),DescriptionInput将使用focus={true}重新呈现。

    <TextInput
       style = {styles.descriptionInput}          
       multiline = {true}
       maxLength = {200}
       placeholder = "Description" 
       focus={this.state.focusDescriptionInput}
    />
    
  5. 这是一种避免使用引用的好方法,因为引用会导致更脆弱的代码:)

    编辑:h / t到@LaneRettig指出你需要用一些添加的道具&amp;来包装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(); 
        }
    

答案 2 :(得分:25)

从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)
  }
}

然后,您可以在任何&#34; ref&#34;上调用focusTextInput函数。一个TextInput。例如:

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

答案 3 :(得分:18)

我创建了一个小型库来执行此操作,除了替换包装视图和导入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/

答案 4 :(得分:11)

使用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>
        )
    }
}

答案 5 :(得分:8)

对于RN 0.50.3,我可以这样做:

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

<TextInput ref={input => {this.PasswordInputRef = input}} />

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

答案 6 :(得分:7)

如果您正好像我一样使用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>
    );
  },
});

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

            mySqlCommand.CommandText = string.Format("INSERT INTO Users (`Full Name`, Birthday, Sex, City, Region, `Zip Code`, Country, `Phone Number`, `Email Address`, `Ticket Number`) VALUES (@Full_Name, @Birthday, @Sex, @City, @Region, @Zip_Code, @Country, @Phone_Number, @Email_Address, @Ticket_Number);");

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

答案 7 :(得分:5)

将@Eli Johnson 的功能组件解决方案与@Rodrigo Tessarollo 的 CustomTextInput 解决方案相结合:

import React, { useRef } from 'react'
...


const MyFormComponent = () => {

  const ref_input2 = useRef();

  return (
    <>
      <TextInput
        placeholder="Input1"
        autoFocus={true}
        returnKeyType="next"
        onSubmitEditing={() => ref_input2.current.focus()}
      />
      <TextInput
        placeholder="Input2"
        returnKeyType="done"
        refInner={ref_input2}
        onSubmitEditing={/* Do something! */}
      />
    </>
  )
}

在您的 CustomTextInput 组件中:

export function CustomTextInput(props) {
  <Input
        ref={props.refInner}
        {...props}
  />
}

答案 8 :(得分:5)

这就是我实现它的方式。下面的示例使用了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>
    );
  }
}

我认为这会对您有所帮助。

答案 9 :(得分:4)

使用回调引用而不是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}
/>

答案 10 :(得分:3)

我的方案是&lt; CustomBoladonesTextInput /&gt; 包裹RN &lt; TextInput /&gt;

我解决了这个问题如下:

我的表单如下:

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

  <CustomBoladonesTextInput 
       ref={ref => this.customInput2 = ref}
       refInner="innerTextInput2"
       ... />

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

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

瞧。一切都恢复正常。 希望这有帮助

答案 11 :(得分:3)

在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>
        );
    }
});

答案 12 :(得分:2)

如果您的TextInput在另一个组件中,则可以使用已接受的解决方案,您需要将ref的引用“弹出”到父容器。

// 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}/>
}

答案 13 :(得分:2)

<TextInput placeholder="Nombre"
    ref="1"
    editable={true}
    returnKeyType="next"
    underlineColorAndroid={'#4DB6AC'}
    blurOnSubmit={false}
    value={this.state.First_Name}
    onChangeText={First_Name => this.setState({ First_Name })}
    onSubmitEditing={() => this.focusNextField('2')}
    placeholderTextColor="#797a7a" style={{ marginBottom: 10, color: '#808080', fontSize: 15, width: '100%', }} />

<TextInput placeholder="Apellido"
    ref="2"
    editable={true}
    returnKeyType="next"
    underlineColorAndroid={'#4DB6AC'}
    blurOnSubmit={false}
    value={this.state.Last_Name}
    onChangeText={Last_Name => this.setState({ Last_Name })}
    onSubmitEditing={() => this.focusNextField('3')}
    placeholderTextColor="#797a7a" style={{ marginBottom: 10, color: '#808080', fontSize: 15, width: '100%', }} />

并添加方法

focusNextField(nextField) {
    this.refs[nextField].focus();
}

答案 14 :(得分:1)

组件中的

*

注意:我使用了"//*[name()='use' and @*='#aaa']" ,因为它是NativeBase'Library' Input

中TextInput的引用

并在您的文字输入中

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();
    }

答案 15 :(得分:1)

有一种方法可以捕获TextInput中的标签。这很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} />
    )
  }
}

答案 16 :(得分:1)

真的很讨厌RN没有某种Tabindex系统。

一个功能组件,对于我的用例,我有一个用于输入的字符串ID数组,这些ID进行迭代并显示每个输入的文本。以下代码将自动使用户跳过所有代码,停止键盘在各字段之间消失/重新出现并在末尾将其关闭,并在键盘上显示相应的“操作”按钮。

打字稿,本机基础。

const stringFieldIDs = [
  'q1', 'q2', 'q3'
];

export default () => {
  const stringFieldRefs = stringFieldIDs.map(() => useRef < any > ());

  const basicStringField = (id: string, ind: number) => {
    const posInd = stringFieldIDs.indexOf(id);
    const isLast = posInd === stringFieldIDs.length - 1;

    return ( <
      Input blurOnSubmit = {
        isLast
      }
      ref = {
        stringFieldRefs[posInd]
      }
      returnKeyType = {
        isLast ? 'done' : 'next'
      }
      onSubmitEditing = {
        isLast ?
        undefined :
          () => stringFieldRefs[posInd + 1].current._root.focus()
      }
      />
    );
  };

  return stringFieldIDs.map(basicStringField);
};

答案 17 :(得分:1)

import React, { useState, useEffect, useRef, } from 'react';

const OTP = (props) => {



    const OTP = [];
    const ref_input = [];
    ref_input[0] = useRef();
    ref_input[1] = useRef();
    ref_input[2] = useRef();
    ref_input[3] = useRef();

    const focusNext = (text, index) => {
        if (index < ref_input.length - 1 && text) {
            ref_input[index + 1].current.focus();
        }
        if (index == ref_input.length - 1) {
            ref_input[index].current.blur();
        }
        OTP[index] = text;
    }
    const focusPrev = (key, index) => {
        if (key === "Backspace" && index !== 0) {
            ref_input[index - 1].current.focus();
        }
    }

    return (
        <SafeAreaView>
            <View>
                
                    <ScrollView contentInsetAdjustmentBehavior="automatic" showsVerticalScrollIndicator={false}>
                        <View style={loginScreenStyle.titleWrap}>
                            <Title style={loginScreenStyle.titleHeading}>Verify OTP</Title>
                            <Subheading style={loginScreenStyle.subTitle}>Enter the 4 digit code sent to your mobile number</Subheading>
                        </View>
                        <View style={loginScreenStyle.inputContainer}>
                            <TextInput
                                mode="flat"
                                selectionColor={Colors.primaryColor}
                                underlineColorAndroid="transparent"
                                textAlign='center'
                                maxLength={1}
                                keyboardType='numeric'
                                style={formScreenStyle.otpInputStyle}
                                autoFocus={true}
                                returnKeyType="next"
                                ref={ref_input[0]}
                                onChangeText={text => focusNext(text, 0)}
                                onKeyPress={e => focusPrev(e.nativeEvent.key, 0)}
                            />
                            <TextInput
                                mode="flat"
                                selectionColor={Colors.primaryColor}
                                underlineColorAndroid="transparent"
                                textAlign='center'
                                maxLength={1}
                                keyboardType='numeric'
                                style={formScreenStyle.otpInputStyle}
                                ref={ref_input[1]}
                                onChangeText={text => focusNext(text, 1)}
                                onKeyPress={e => focusPrev(e.nativeEvent.key, 1)}
                            />
                            <TextInput
                                mode="flat"
                                selectionColor={Colors.primaryColor}
                                underlineColorAndroid="transparent"
                                textAlign='center'
                                maxLength={1}
                                keyboardType='numeric'
                                style={formScreenStyle.otpInputStyle}
                                ref={ref_input[2]}
                                onChangeText={text => focusNext(text, 2)}
                                onKeyPress={e => focusPrev(e.nativeEvent.key, 2)}
                            />
                            <TextInput
                                mode="flat"
                                selectionColor={Colors.primaryColor}
                                underlineColorAndroid="transparent"
                                textAlign='center'
                                maxLength={1}
                                keyboardType='numeric'
                                style={formScreenStyle.otpInputStyle}
                                ref={ref_input[3]}
                                onChangeText={text => focusNext(text, 3)}
                                onKeyPress={e => focusPrev(e.nativeEvent.key, 3)}
                            />

                        </View>
                    </ScrollView>
            </View>
        </SafeAreaView >
    )
}

export default OTP;

答案 18 :(得分:1)

这是 reactjs 电话代码输入的实现方法

import React, { useState, useRef } from 'react';

function Header(props) {

  const [state , setState] = useState({
        phone_number:"",
        code_one:'',
        code_two:'',
        code_three:'',
        code_four:'',
        submitted:false,

  })

   const codeOneInput = useRef(null);
   const codeTwoInput = useRef(null);
   const codeThreeInput = useRef(null);
   const codeFourInput = useRef(null);

   const handleCodeChange = (e) => {
        const {id , value} = e.target
        if(value.length < 2){
            setState(prevState => ({
                ...prevState,
                [id] : value
            }))
            if(id=='code_one' && value.length >0){
                codeTwoInput.current.focus();
            }
            if(id=='code_two'  && value.length >0){
                codeThreeInput.current.focus();
            }
            if(id=='code_three'  && value.length >0){
                codeFourInput.current.focus();
            }
        }
    }

    const sendCodeToServer = () => {

         setState(prevState => ({
                ...prevState,
                submitted : true,
          }))
  let codeEnteredByUser = state.code_one + state.code_two + state.code_three + state.code_four

        axios.post(API_BASE_URL, {code:codeEnteredByUser})
        .then(function (response) {
            console.log(response)
        })

   }

   return(
        <>

           <div className="are">
                 <div className="POP-INN-INPUT">
                                        <input type="text" id="code_one" ref={codeOneInput}    value={state.code_one}  onChange={handleCodeChange} autoFocus/>
                                        <input type="text" id="code_two"  ref={codeTwoInput}  value={state.code_two} onChange={handleCodeChange}/>
                                        <input type="text" id="code_three"  ref={codeThreeInput} value={state.code_three}  onChange={handleCodeChange}/>
                                        <input type="text" id="code_four" ref={codeFourInput}  value={state.code_four}  onChange={handleCodeChange}/>
                                    </div>

            <button disabled={state.submitted} onClick={sendCodeToServer}>
   
    </div>

       </>
    )
}
export default

enter image description here

答案 19 :(得分:0)

此处为输入组件的试剂溶液,具有:focus属性。

只要此道具设置为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

答案 20 :(得分:0)

如果您将NativeBase用作UI组件,则可以使用此示例


         <Item floatingLabel>
              <Label>Title</Label>
              <Input
              returnKeyType = {"next"}
              autoFocus = {true}
              onSubmitEditing={(event) => {
                  this._inputDesc._root.focus(); 
              }}
              />
          </Item>
          <Item floatingLabel>
              <Label>Description</Label>
              <Input
              getRef={(c) => this._inputDesc = c}
              multiline={true} style={{height: 100}} />
              onSubmitEditing={(event) => { this._inputLink._root.focus(); }}
          </Item>```

答案 21 :(得分:0)

<TextInput 
    keyboardType="email-address"
    placeholder="Email"
    returnKeyType="next"
    ref="email"
    onSubmitEditing={() => this.focusTextInput(this.refs.password)}
    blurOnSubmit={false}
 />
<TextInput
    ref="password"
    placeholder="Password" 
    secureTextEntry={true} />

并为onSubmitEditing={() => this.focusTextInput(this.refs.password)}添加方法,如下所示:

private focusTextInput(node: any) {
    node.focus();
}

答案 22 :(得分:-2)

在自定义组件中添加一个方法,该方法将返回对TextInput的引用。 获取对您的自定义组件的引用,然后在该引用上调用方法。

getInnerRef = () => this.ref;

render() {
    return (
        <View>
            <TextInput
                {...this.props}
                ref={(r) => this.ref = r}
            />
        </View>
    )
}

render() {
    return (
        <View>
            <CustomTextInput
                onSubmitEditing={() => this.refInput.getInnerRef().focus()}
            />
            <CustomTextInput
                {...this.props}
                ref={(r) => this.refInput = r}
            />
        </View>
    )
}

最初由 basbase here回答。