我想将光标焦点移动到屏幕上的前一个textInput上。 onkeyPress无法正常工作,因为该功能仅适用于IOS平台,不适用于Android。那么如何在Android平台中阻止这种方法呢?
TextInput的示例代码:
<TextInput style = {styles.input}
keyboardType='numeric'
maxLength={1}
ref="otpcode1"
onChangeText={(event) => {
this.setState({otp1: event});
this.refs.otpcode2.focus() }}
underlineColorAndroid='#fff'/>
<TextInput style = {styles.input}
keyboardType='numeric'
maxLength={1}
ref="otpcode2"
onChangeText={(event) => {
this.setState({otp2: event});
this.refs.otpcode3.focus() }}
underlineColorAndroid='#fff'/>
<TextInput style = {styles.input}
keyboardType='numeric'
maxLength={1}
ref="otpcode3"
onChangeText={(event) => {
this.setState({otp3: event});
this.refs.otpcode4.focus() }}
underlineColorAndroid='#fff'/>
<TextInput style = {styles.input}
keyboardType='numeric'
maxLength={1}
ref="otpcode4"
onChangeText={(event) => {
this.setState({otp4: event});
console.log(this.state) }}
underlineColorAndroid='#fff'/>
答案 0 :(得分:2)
您应该只使用onKeyPress
中的TextInput
道具,并检测keyValue
是BackSpace的时间,以专注于先前的TextInput
,诸如此类:
onKeyPress
在最新版本的React-Native上可在iOS和Android上运行,因此以下示例应可运行:
class Test extends Component {
constructor() {
super();
this.handleKeyPress = this.handleKeyPress.bind(this);
}
render() {
return (
<TextInput
onKeyPress={ this.handleKeyPress }
/>
)
}
handleKeyPress({ nativeEvent: { key: keyValue } }) {
if (keyValue === 'Backspace') {
this.refs.refOfPreviousInput.focus();
}
}
}
但是您使用的是老版本的react-native,您可以在onChangeText
或onChange
中处理它,只需检查您的值length
,如果是为0时将焦点放在先前的输入上:
class Test extends Component {
constructor() {
super();
this.handleKeyPress = this.handleKeyPress.bind(this);
}
render() {
return (
<TextInput
onChangeText={ this.handleChangeText }
/>
)
}
handleChangeText(value) {
if (value.length === 0) {
this.refs.refOfPreviousInput.focus();
}
}
}
这不是完整的代码,但是向您展示了如何处理它。 希望对您有所帮助!
答案 1 :(得分:0)
有同样的问题,做了一个肮脏的解决方案,但它的工作原理 逻辑和问题的解释都在代码中。
用法:
import {Alert} from 'react-native';
onPinEntered = (pin) => {
Alert.alert(
'Entered pin',
pin,
[{text: 'OK'}]
)
}
render() {
return (
<PinInput onPinEntered={this.onPinEntered}/>
)
}
成分:
import React, {PureComponent} from 'react';
import {
Platform,
StyleSheet,
TextInput,
View,
Text,
TouchableWithoutFeedback,
Keyboard,
Animated
} from 'react-native';
import PropTypes from 'prop-types';
// import ui_size from '../tools/UISizer';
let ui_size = function(points){
//simple sizing function (it project it handles complex screen adaptation)
return points*2
}
//Main technical problems:
//1. At date of development RN doesn't provide onKeyPress for android platform
//2. Changing text and selection of TextInput at same time is extremely buggy
//Solution:
//Create TextInput with maxLength = 2 and always prefilled with empty_character = ' ', (value={empty_character})
//add self-written cursor pointer
//track changes of text, if new text is '', backspace was pressed - move cursor to left by 1
// if new text is not empty, add new character to buffer (state.pin), mover cursor to right by 1
//Some times during reloads, selection is setting before defaultValue of TextInput and raises setSpan error (at least on Android)
// so additionally track focused state (in render this.input.isFocused() raises strange error:
// "TypeError owner.getName is not a function")
//On android, when input is focused and user hides keyboard by back button, it can only be shown by tap on input
// (.focus() don't show keyboard if input is already focused), so track it and blur the input
const empty_character = ' '
export default class PinInput extends PureComponent {
static defaultProps = {
maxChars: 4,
inputProps: {},
};
static propTypes = {
maxChars: PropTypes.number,
onPinEntered: PropTypes.func,
inputProps: PropTypes.object,
};
constructor(props) {
super(props);
this.state = {
pin: '', // entered pin
selection: undefined, // cursor position
isFocused: false,
blinkAnim: new Animated.Value(1),
isLastCharUpdated: false, // track if last character was updated
}
}
onPressCell = (event, id) => {
let {pin} = this.state
// by pressing on unfilled cell, set cursor next to last filled cell
if (id > pin.length) {
id = pin.length
}
// set cursor position
this.setState({
selection: id,
})
this.input.focus()
}
cycleBlinkAnimation = () => {
Animated.sequence([
Animated.timing(this.state.blinkAnim, {
toValue: 0,
duration: 1000
}),
Animated.timing(this.state.blinkAnim, {
toValue: 1,
duration: 50
}),
Animated.timing(this.state.blinkAnim, {
toValue: 1,
duration: 300
})
]).start((event) => {
if (event.finished && this.state.isFocused) {
this.cycleBlinkAnimation()
}
})
}
onFocus = (event) => {
console.log('onFocus')
let {selection} = this.state
// update cursor position only if it wasn't setted up
if (selection === undefined) {
selection = 0
}
this.setState({
selection,
isFocused: true,
})
}
onBlur = (event) => {
console.log('onBlur')
this.setState({
selection: undefined,
isFocused: false,
isLastCharUpdated: false,
})
}
componentWillUpdate(nextProps, nextState) {
if (this.state.isFocused && !nextState.isFocused) {
this.state.blinkAnim.stopAnimation()
}
//restart animation on focus or when cursor moved
if ((this.state.selection !== nextState.selection || !this.state.isFocused) && nextState.isFocused) {
this.state.blinkAnim.stopAnimation(() => {
this.state.blinkAnim.setValue(1)
this.cycleBlinkAnimation()
})
}
}
componentDidUpdate(prevProps, prevState) {
if (this.state.isFocused
&& this.state.pin.length === this.props.maxChars // input is full
&& this.state.selection+1 === this.props.maxChars // cursor is in last cell
// && prevState.pin[3] !== this.state.pin[3]) { // last cell was changed
&& this.state.isLastCharUpdated) {
console.log('blur componentDidUpdate')
this.input.blur()
setTimeout(this.onPinEntered, 1) // dirty hack, on ios sync call onPinEntered prevents blur
}
}
componentWillMount() {
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide);
}
componentDidMount() {
this.cycleBlinkAnimation()
}
componentWillUnmount() {
this.keyboardDidHideListener.remove()
}
keyboardDidHide = () => {
// see reason in top
// to prevent unfocussing in IOS simulator with connected hardware keyboard uncomment the following line
// or disconnect hardware keyboard by unchecking simulator > Hardware > Keyboard > Connect Hardware Keyboard
// if (Platform.OS === 'ios') return;
if (this.state.isFocused) {
this.input.blur()
}
}
onChangeText = (text) => {
let {pin, selection} = this.state
text = text.replace(empty_character, '') //remove first occurrence of empty_character
let str_replaceAt = function (string, index, replacement) {
return string.substr(0, index) + replacement + string.substr(index + 1);
}
let isLastCharUpdated = false
if (text.length === 0) { //backspace
pin = str_replaceAt(pin, selection, '')
selection -= 1
selection = Math.max(selection, 0)
} else { //character entered
pin = str_replaceAt(pin, selection, text)
selection += 1
if (selection >= this.props.maxChars) {
isLastCharUpdated = true
}
selection = Math.min(selection, this.props.maxChars - 1)
}
this.setState({pin, selection, isLastCharUpdated})
}
onPinEntered = () => {
if ('function' === typeof this.props.onPinEntered) {
this.props.onPinEntered(this.state.pin)
}
}
render_cell(id, value, is_active) {
let style = (is_active) ? [styles.cell, styles.active_cell] : styles.cell
let animation_style =
[styles.cursor, {
opacity: this.state.blinkAnim, // Bind opacity to animated value
}]
return (
<TouchableWithoutFeedback key={id} onPress={(event) => this.onPressCell(event, id)}>
<View>
<Text style={style}>{value}</Text>
{ is_active && <Animated.View style={animation_style} />}
</View>
</TouchableWithoutFeedback>
)
}
render() {
let inputs = []
let {pin, selection} = this.state
//render cells
for (let i = 0; i < this.props.maxChars; i++) {
inputs.push(this.render_cell(i, pin[i], (selection === i)))
}
// place cursor after empty_character
let input_selection = undefined
// as described in top: Some times during reloads, selection is setting before defaultValue ...
if (this.input !== undefined && this.state.isFocused) {
// so set selection after first character (empty_character) only when input is focused
input_selection = {start: 1, end: 1}
}
let root_style = [this.props.style || {}, styles.root]
return (
<View style={root_style}>
<TextInput
style={styles.actual_input}
ref={(input) => this.input = input}
maxLength={2}
selection={input_selection}
onChangeText={this.onChangeText}
autoComplete={false}
autoCorrect={false}
defaultValue={empty_character}
value={empty_character}
onFocus={this.onFocus}
onBlur={this.onBlur}
onSubmitEditing={this.onPinEntered}
{...this.props.inputProps}
/>
<View style={styles.cells_wrapper}>
{inputs}
</View>
</View>
)
}
}
const styles = StyleSheet.create({
root: {},
actual_input: {
position: 'absolute',
display: 'none',
},
cells_wrapper: {
flexDirection: 'row',
},
cell: {
height: ui_size(24.8),
width: ui_size(19.2),
textAlign: 'center',
elevation: 10,
fontSize: ui_size(18),
lineHeight: ui_size(24),
backgroundColor: 'white',
color: 'black',
fontWeight: 'bold',
paddingHorizontal: ui_size(3),
margin: ui_size(6.7) / 2,
borderRadius: ui_size(2.5),
borderBottomColor: 'transparent',
zIndex: 1,
overflow: 'hidden', // crop corners in IOS
},
active_cell: {
color: 'rgba(0,0,0,0.4)',
},
cursor: {
position: 'absolute',
height: 1,
width: '50%',
left: '25%',
bottom: 12,
borderBottomColor: 'rgba(0,0,0,0.5)',
borderBottomWidth: 1,
zIndex: 2,
elevation: 10,
}
});