React Native:如何在按下“next”键后选择下一个文本输入键盘按钮?

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

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

但在按下键盘上的“next”按钮后,我的react-native应用程序并没有跳转到第二个TextInput字段。我怎样才能做到呢?

谢谢!

322977 次浏览

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

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

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

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

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

试试这个

  1. 第二个TextInput添加Ref
    ref={(input) => { this.secondTextInput = input; }} < / p > < / >

  2. 绑定焦点函数到第一个TextInput的onSubmitEditing事件 李onSubmitEditing={() => { this.secondTextInput.focus(); }} < / p > < / >

  3. 记住将blurOnSubmit设置为false,以防止键盘闪烁 李blurOnSubmit={false} < / p > < / >

当一切都完成后,它应该看起来像这样。

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


<TextInput
ref={(input) => { this.secondTextInput = input; }}
placeholder="secondTextInput"
/>

你可以这样做不使用裁判。这种方法是首选的,因为refs可以导致脆弱的代码反应文档建议在可能的情况下寻找其他解决方案:

如果你还没有使用React编写多个应用程序,那么你的第一个应用程序就是React 通常倾向于尝试使用裁判来“制造东西” 如果是这样的话,花点时间好好想想 关键在于组件中应该在哪里拥有状态 层次结构。通常情况下,“拥有”它的合适位置会变得很清楚 State在层次结构中处于更高的层次。把状态放在那里 经常消除任何欲望使用裁判“使事情发生”- 相反,数据流通常会实现你的目标

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

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

    initialState() {
    return {
    focusDescriptionInput: false,
    };
    }
    
  2. Define a handler method that will set this state variable to true:

    handleTitleInputSubmit() {
    this.setState(focusDescriptionInput: true);
    }
    
  3. Upon submitting / hitting enter / next on the TitleInput, we'll call handleTitleInputSubmit. This will set focusDescriptionInput to true.

    <TextInput
    style = {styles.titleInput}
    returnKeyType = {"next"}
    autoFocus = {true}
    placeholder = "Title"
    onSubmitEditing={this.handleTitleInputSubmit}
    />
    
  4. DescriptionInput's focus prop is set to our focusDescriptionInput state variable. So, when focusDescriptionInput changes (in step 3), DescriptionInput will re-render with focus={true}.

    <TextInput
    style = {styles.descriptionInput}
    multiline = {true}
    maxLength = {200}
    placeholder = "Description"
    focus={this.state.focusDescriptionInput}
    />
    

This is a nice way to avoid using refs, since refs can lead to more fragile code :)

EDIT: h/t to @LaneRettig for pointing out that you'll need to wrap the React Native TextInput with some added props & methods to get it to respond to focus:

    // Props:
static propTypes = {
focus: PropTypes.bool,
}


static defaultProps = {
focus: false,
}


// Methods:
focus() {
this._component.focus();
}


componentWillReceiveProps(nextProps) {
const {focus} = nextProps;


focus && this.focus();
}

如果你碰巧像我一样使用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)

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

只要这个道具设置为true,字段就会被聚焦;如果这个道具设置为false,字段就不会有焦点。

不幸的是,这个组件需要定义一个: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

有一种方法可以在TextInput中捕获选项卡。这有点俗气,但比没有什么好。

定义一个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} />
)
}
}

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

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

从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" />
...

如果你的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}/>
}

使用react-native 0.45.1我还遇到了问题,试图在按下用户名TextInput的返回键后将焦点设置在密码TextInput上。

在尝试了这里的大多数顶级解决方案之后,我在github上找到了一个解决方案,满足了我的需求: https://github.com/shoutem/ui/issues/44#issuecomment-290724642 < / p >

总结一下:

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

我创建了一个小库来做这件事,除了替换你的包装视图和导入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/

在你的组件中:

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”输入中的TextInput的引用

在文本输入中,像这样

<TextInput
onSubmitEditing={() => {
this.focusNextField('two');
}}
returnKeyType="next"
blurOnSubmit={false}/>




<TextInput
ref={input => {
this.inputs['two'] = input;
}}/>

我的场景是& lt;CustomBoladonesTextInput / >包装一个RN & lt;TextInput / >

我是这样解决这个问题的:

我的表单是这样的:

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


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

在CustomBoladonesTextInput的组件定义中,我像这样将refField传递给内部的ref道具:

   export default class CustomBoladonesTextInput extends React.Component {
render() {
return (< TextInput ref={this.props.refInner} ... />);
}
}
< p >瞧。一切恢复正常。 希望这对你有所帮助

对于RN 0.50.3的我来说,这是可能的:

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


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

你必须看到这个。

我就是这样做到的。下面的例子使用了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>
);
}
}

我想这对你有帮助。

如果你正在使用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>
<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%', }} />

和add方法

focusNextField(nextField) {
this.refs[nextField].focus();
}
<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();
}

我想分享我的解决方案使用功能组件…''不需要!

React 16.12.0和React Native 0.61.5

这是我的组件的一个例子:

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




const MyFormComponent = () => {


const ref_input2 = useRef();
const ref_input3 = useRef();


return (
<>
<TextInput
placeholder="Input1"
autoFocus={true}
returnKeyType="next"
onSubmitEditing={() => ref_input2.current.focus()}
/>
<TextInput
placeholder="Input2"
returnKeyType="next"
onSubmitEditing={() => ref_input3.current.focus()}
ref={ref_input2}
/>
<TextInput
placeholder="Input3"
ref={ref_input3}
/>
</>
)
}

RN没有某种类型的Tabindex系统,这很令人恼火。

一个功能性组件,对于我的用例,我有一个字符串id数组用于输入,我遍历并显示每个文本输入。下面的代码将自动跳过所有这些字段,停止键盘在字段之间消失/重新出现,并在结束时解散它,还显示适当的“动作”。键盘上的按钮。

Typescript, Native Base。

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

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;

下面是如何为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

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

import React, { useRef } from 'react';
import { CustomTextInput } from 'path/to/CustomTextInput';
...




export const MyFormComponent = () => {


const ref_to_input2 = useRef();


return (
<>
<CustomTextInput
placeholder="Input 1"
autoFocus={true}
returnKeyType="next"
onSubmitEditing={() => ref_to_input2.current.focus()}
/>
<CustomTextInput
placeholder="Input 2"
returnKeyType="done"
refInner={ref_to_input2}
onSubmitEditing={/* Do something! */}
/>
</>
)
}

在你的CustomTextInput组件中:

import { TextInput } from "react-native";
export const CustomTextInput = (props) => {
<TextInput
ref={props.refInner}
{...props}
/>
}