我定义了两个 TextInput 字段,如下所示:
<TextInput
style = {styles.titleInput}
returnKeyType = {"next"}
autoFocus = {true}
placeholder = "Title" />
<TextInput
style = {styles.descriptionInput}
multiline = {true}
maxLength = {200}
placeholder = "Description" />
但是在按下键盘上的“下一步”按钮后,我的 react-native 应用程序并没有跳转到第二个 TextInput 字段。我怎样才能做到这一点?
谢谢!
v16.8.0
或更高版本的人,我建议将@Eli Johnson 提供的答案放在底部。 React 已弃用以下解决方案中提供的 ref
的许多用途。
当前一个 TextInput
的 onSubmitEditing
被触发时,设置第二个 TextInput
焦点。
尝试这个
将 Ref 添加到第二个 TextInput ref={(input) => { this.secondTextInput = input; }} 将焦点函数绑定到第一个 TextInput 的 onSubmitEditing 事件。 onSubmitEditing={() => { this.secondTextInput.focus(); }} 记得将 blurOnSubmit 设置为 false,以防止键盘闪烁。 blurOnSubmit={假}
完成后,它应该看起来像这样。
<TextInput
placeholder="FirstTextInput"
returnKeyType="next"
onSubmitEditing={() => { this.secondTextInput.focus(); }}
blurOnSubmit={false}
/>
<TextInput
ref={(input) => { this.secondTextInput = input; }}
placeholder="secondTextInput"
/>
以为我会使用功能组件分享我的解决方案……不需要“这个”!
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}
/>
</>
)
}
blurOnSubmit={false}
以防止键盘闪烁
你可以做到这一点不使用引用。这种方法是首选,因为 refs 会导致脆弱的代码。 React docs 建议尽可能寻找其他解决方案:
如果你没有用 React 编写过几个应用程序,你的第一个倾向通常是尝试在你的应用程序中使用 refs 来“让事情发生”。如果是这种情况,请花点时间更批判地思考在组件层次结构中应该拥有状态的位置。通常,很明显“拥有”该状态的适当位置位于层次结构中的更高级别。将状态放置在那里通常会消除使用 refs 来“让事情发生”的任何愿望——相反,数据流通常会实现您的目标。
相反,我们将使用状态变量来关注第二个输入字段。
添加一个状态变量,我们将作为道具传递给 DescriptionInput: initialState() { return { focusDescriptionInput: false, };定义一个处理方法,将这个状态变量设置为 true:handleTitleInputSubmit() { this.setState(focusDescriptionInput: true);在 TitleInput 上提交/点击 enter/next 后,我们将调用 handleTitleInputSubmit。这会将 focusDescriptionInput 设置为 true。
这是避免使用 refs 的好方法,因为 refs 会导致代码更脆弱:)
编辑:h/t to @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();
}
从 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" />
...
<Field ... onSubmitEditing={() => focusTextInput(this._password)} />
和 ref 应该是这样的 <Field ... withRef refName={e => this._password = e}/>
calling focus() on a text input node isn't supported any more
=>大胆的主张,来源?调用 focus()
与 v0.49.5 一起工作正常 + TextInputState
没有记录,而提到 focus()
和 blur()
:facebook.github.io/react-native/releases/next/docs/…
我创建了一个小型库来执行此操作,除了替换包装视图和导入 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/
使用 react-native 0.45.1 在用户名 TextInput 上按返回键后,我在尝试将焦点设置在密码 TextInput 上时也遇到了问题。
在 SO 上尝试了大多数最受好评的解决方案后,我在 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>
)
}
}
ref
重命名为 inputRef
...您可以删除整个自定义组件,只要您恢复使用 ref
,您的第二个代码块就会按原样工作
对我来说,RN 0.50.3 可以这样:
<TextInput
autoFocus={true}
onSubmitEditing={() => {this.PasswordInputRef._root.focus()}}
/>
<TextInput ref={input => {this.PasswordInputRef = input}} />
你必须看到 this.PasswordInputRef._root.focus()
我的场景是 < CustomBoladonesTextInput /> 包装了一个 RN < 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} ... />);
}
}
瞧。一切恢复正常。希望这可以帮助
将 @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}
/>
}
如果您碰巧像我一样使用 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)
这就是我实现它的方式。下面的示例使用了 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>
);
}
}
我想这会对你有所帮助。
在 React Native 的 GitHub 问题上尝试这个解决方案。
https://github.com/facebook/react-native/pull/2149#issuecomment-129262565
您需要为 TextInput 组件使用 ref 属性。然后,您需要创建一个在 onSubmitEditing 道具上调用的函数,该道具将焦点移到第二个 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>
);
}
});
<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();
}
使用回调引用而不是 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}
/>
如果您的 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}/>
}
在您的组件中:
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;
}}/>
<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();
}
这是 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
https://i.stack.imgur.com/bTArU.png
有一种方法可以在 TextInput
中捕获标签。它很老套,但比 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} />
)
}
}
RN 没有某种 Tabindex 系统真的很烦人。
一个功能组件,对于我的用例,我有一组用于输入的字符串 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() } /> ); };返回 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;
如果您使用 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>
这里是具有 :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
atom
类型上显式调用 swap!
之类的事情来实现。根据文档,这用于绑定到 React:“任何使用原子的组件都会在其值更改时自动重新渲染。” reagent-project.github.io
blur
事件之后调用了onSubmitEditing
回调。因此,如果立即关注下一个元素,键盘可能会发疯。因此,将blurOnSubmit={false}
设置为表单中的所有元素但在最后一个元素上保留true
可能会有所帮助,以允许 Done 按钮模糊最后一个输入。blurOnSubmit={false}
以防止键盘闪烁导致它停止工作,有谁知道发生了什么?focus
工作的任何人,请确保您没有为TextInput
组件使用包装器。如果您有一个包装TextInput
的 sayCustomTextInput
组件,则需要为该组件实现TextInput
blur 和 focus 方法,以便它按预期工作。