Javascript 如何在反应原生上自动聚焦下一个 TextInput
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42371023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to autofocus next TextInput on react-native
提问by J.Doe
I'm trying to create a passcode protected screen. The screen will uses 4 numeric input as the passcode.
我正在尝试创建一个受密码保护的屏幕。屏幕将使用 4 个数字输入作为密码。
The way I'm doing this is create a TextInput Component and call it 4 times in my main screen.
我这样做的方法是创建一个 TextInput 组件并在我的主屏幕中调用它 4 次。
The problem I'm having is the TextInputs will not focus on the next one as I type the value of the previous TextInput.
我遇到的问题是当我输入前一个 TextInput 的值时,TextInputs 不会关注下一个。
I'm using refs for all PasscodeTextInput component (I've been informed that it is a legacy method but I do not know any other way, alas).
我正在为所有 PasscodeTextInput 组件使用 refs(我被告知这是一个遗留方法,但我不知道任何其他方式,唉)。
Tried this method(without creating my own component), no luck too.METHOD
试过这个方法(没有创建我自己的组件),也没有运气。方法
index.ios.js
index.ios.js
import React, { Component } from 'react';
import { AppRegistry, TextInput, View, Text } from 'react-native';
import { PasscodeTextInput } from './common';
export default class ProgressBar extends Component {
render() {
const { centerEverything, container, passcodeContainer, textInputStyle} = styles;
return (
<View style={[centerEverything, container]}>
<View style={[passcodeContainer]}>
<PasscodeTextInput
autoFocus={true}
ref="passcode1"
onSubmitEditing={(event) => { this.refs.passcode2.focus() }} />
<PasscodeTextInput
ref="passcode2"
onSubmitEditing={(event) => { this.refs.passcode3.focus() }} />
<PasscodeTextInput
ref="passcode3"
onSubmitEditing={(event) => { this.refs.passcode4.focus() }}/>
<PasscodeTextInput
ref="passcode4" />
</View>
</View>
);
}
}
const styles = {
centerEverything: {
justifyContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#E7DDD3',
},
passcodeContainer: {
flexDirection: 'row',
},
}
AppRegistry.registerComponent('ProgressBar', () => ProgressBar);
PasscodeTextInput.js
密码文本输入.js
import React from 'react';
import {
View,
Text,
TextInput,
Dimensions
} from 'react-native';
const deviceWidth = require('Dimensions').get('window').width;
const deviceHeight = require('Dimensions').get('window').height;
const PasscodeTextInput = ({ ref, autoFocus, onSubmitEditing, onChangeText, value}) => {
const { inputStyle, underlineStyle } = styles;
return(
<View>
<TextInput
ref={ref}
autoFocus={autoFocus}
onSubmitEditing={onSubmitEditing}
style={[inputStyle]}
maxLength={1}
keyboardType="numeric"
placeholderTextColor="#212121"
secureTextEntry={true}
onChangeText={onChangeText}
value={value}
/>
<View style={underlineStyle} />
</View>
);
}
const styles = {
inputStyle: {
height: 80,
width: 60,
fontSize: 50,
color: '#212121',
fontSize: 40,
padding: 18,
margin: 10,
marginBottom: 0
},
underlineStyle: {
width: 60,
height: 4,
backgroundColor: '#202020',
marginLeft: 10
}
}
export { PasscodeTextInput };
Update 1
更新 1
index.ios.js
index.ios.js
import React, { Component } from 'react';
import { AppRegistry, TextInput, View, Text } from 'react-native';
import { PasscodeTextInput } from './common';
export default class ProgressBar extends Component {
constructor() {
super()
this.state = {
autoFocus1: true,
autoFocus2: false,
autoFocus3: false,
autoFocus4: false,
}
}
onTextChanged(t) { //callback for immediate state change
if (t == 2) { this.setState({ autoFocus1: false, autoFocus2: true }, () => { console.log(this.state) }) }
if (t == 3) { this.setState({ autoFocus2: false, autoFocus3: true }, () => { console.log(this.state) }) }
if (t == 4) { this.setState({ autoFocus3: false, autoFocus4: true }, () => { console.log(this.state) }) }
}
render() {
const { centerEverything, container, passcodeContainer, testShit, textInputStyle } = styles;
return (
<View style={[centerEverything, container]}>
<View style={[passcodeContainer]}>
<PasscodeTextInput
autoFocus={this.state.autoFocus1}
onChangeText={() => this.onTextChanged(2)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus2}
onChangeText={() => this.onTextChanged(3)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus3}
onChangeText={() => this.onTextChanged(4)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus4} />
</View>
</View>
);
}
}
const styles = {
centerEverything: {
justifyContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#E7DDD3',
},
passcodeContainer: {
flexDirection: 'row',
},
}
AppRegistry.registerComponent('ProgressBar', () => ProgressBar);
回答by Mukundhan
There is a defaultProp for TextInput where one can focus after component mounted.
TextInput 有一个 defaultProp,可以在组件安装后聚焦。
autoFocus
自动对焦
If true, focuses the input on componentDidMount, the default value is false. for more information please read the related Docs.
如果为 true,则将输入重点放在 componentDidMount 上,默认值为 false。有关更多信息,请阅读相关文档。
UPDATE
更新
After componentDidUpdateit won't work properly. In that case, one can use refto focus programmatically.
之后componentDidUpdate就不能正常使用了。在这种情况下,可以使用ref以编程方式聚焦。
回答by max23_
You cannot forward the refto <TextInput>using that way because refis one of the special props. Thus, calling this.refs.passcode2will return you <PasscodeTextInput>instead.
您不能使用这种方式转发refto <TextInput>,因为它ref是特殊道具之一。因此,调用this.refs.passcode2将返回您<PasscodeTextInput>。
Try change to the following to get the reffrom <TextInput>.
尝试更改为以下内容以获取reffrom <TextInput>.
PasscodeTextInput.js
密码文本输入.js
const PasscodeTextInput = ({ inputRef, ... }) => {
...
return (
<View>
<TextInput
ref={(r) => { inputRef && inputRef(r) }}
...
/>
</View>
...
);
}
Then, assign the inputReffrom <PasscodeTextInput>to a variable and use focus()to switch focus (it is not deprecated as of RN 0.41.2).
然后,将inputReffrom分配给<PasscodeTextInput>变量并用于focus()切换焦点(自 RN 起不推荐使用0.41.2)。
index.ios.js
index.ios.js
return (
<PasscodeTextInput
autoFocus={true}
onChangeText={(event) => { event && this.passcode2.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode2 = r }}
onChangeText={(event) => { event && this.passcode3.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode3 = r }}
onChangeText={(event) => { event && this.passcode4.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode4 = r }} />
);
P.S: event && this.passcode2.focus()prevents focus is switched when trying to clear the old passcode and enter a new one.
PS:event && this.passcode2.focus()防止在尝试清除旧密码并输入新密码时切换焦点。
回答by crafterm
we handled this style of screen with a different approach.
我们用不同的方法处理这种风格的屏幕。
Rather than manage 4 individual TextInputs and handle the navigation of focus across each one (and then back again when the user deletes a character), we have a single TextInput on screen but is invisible (ie. 0px x 0px) wide which has the focus, maxLength and keyboard configuration, etc.
我们没有管理 4 个单独的 TextInputs 并处理每个 TextInputs 的焦点导航(然后在用户删除字符时再次返回),我们在屏幕上有一个 TextInput 但不可见(即 0px x 0px)宽,它具有焦点, maxLength 和键盘配置等。
This TextInput takes input from the user but can't actually been seen, as each character is typed in we render the entered text as a series simple View/Text elements, styled much similar to your screen above.
这个 TextInput 接受来自用户的输入但实际上不能被看到,因为每个字符都是输入的,我们将输入的文本呈现为一系列简单的 View/Text 元素,样式与上面的屏幕非常相似。
This approach worked well for us with no need to manage what the 'next' or 'previous' TextInput to focus next to.
这种方法对我们来说效果很好,无需管理要关注的“下一个”或“上一个”TextInput。
回答by eden
You can use focus method onChangeTextas Jason stated, in addition to that adding maxLength={1}can make you jump to the next input immediately without checking what's added. (just noticed its deprecated, but still this is how I solved my problem, and should do fine until v0.36, and this linkexplains how you should update the deprecated function).
您可以使用onChangeTextJason 所说的focus 方法,此外,添加maxLength={1}可以让您立即跳转到下一个输入,而无需检查添加的内容。(只是注意到它已弃用,但这仍然是我解决我的问题的方法,并且在 v0.36 之前应该可以正常工作,并且此链接解释了您应该如何更新已弃用的函数)。
<TextInput
ref="first"
style={styles.inputMini}
maxLength={1}
keyboardType="numeric"
returnKeyType='next'
blurOnSubmit={false}
placeholderTextColor="gray"
onChangeText={(val) => {
this.refs['second'].focus()
}}
/>
<TextInput
ref="second"
style={styles.inputMini}
maxLength={1}
keyboardType="numeric"
returnKeyType='next'
blurOnSubmit={false}
placeholderTextColor="gray"
onChangeText={(val) => {
this.refs['third'].focus()
}}
/>
...
Please notice that my use of refs are deprecated too, but I've just copied the code since I can guarantee you that was working back then (hopefully works now too).
请注意,我对 refs 的使用也已被弃用,但我刚刚复制了代码,因为我可以向您保证当时可以使用(希望现在也可以使用)。
Finally, the main issue with this type of implementation is, once you try to remove a number with backspace your focus will jump to next one, causing serious UX issues. However, you can listen for backspace key entry and perform something different instead of focusing to next input. So I'll leave a linkhere for you to further investigate if you choose to use this type of implementation.
最后,这种类型的实现的主要问题是,一旦您尝试使用退格键删除一个数字,您的焦点将跳转到下一个,从而导致严重的 UX 问题。但是,您可以监听退格键输入并执行不同的操作,而不是专注于下一个输入。因此,如果您选择使用这种类型的实现,我将在此处留下一个链接供您进一步调查。
Hacky Solution to Previously Described Issue:If you check what's entered in onChangeTextprop before doing anything, you can jump to next input if the value is a number, else (that's a backspace), jump back. (Just came up with this idea, I haven't tried it.)
先前描述的问题的黑客解决方案:如果您onChangeText在做任何事情之前检查prop 中输入的内容,如果值是数字,您可以跳到下一个输入,否则(这是一个退格),跳回。(刚想出这个主意,我还没试过。)
回答by noe
<TextInput
ref={input => {
this.nameOrId = input;
}}
/>
<TouchableOpacity
onPress={()=>{
this.nameOrId.focus()
}}
>
<Text>Click</Text>
</TouchableOpacity>
回答by Jason Gaare
I think the issue is that onSubmitEditingis when you hit the "return" or "enter" key on the regular keyboard... there is not one of those buttons on the keypad.
我认为问题在于onSubmitEditing当您按下常规键盘上的“返回”或“输入”键时……键盘上没有这些按钮之一。
Assuming you want each input to only have one character, you could look at the onChangeTextand then check if text has length 1 and call focus if the length is indeed 1.
假设您希望每个输入只有一个字符,您可以查看onChangeText然后检查文本的长度是否为 1,如果长度确实为 1,则调用焦点。


