如何在react-native上自动对焦下一个TextInput

时间:2017-02-21 15:08:50

标签: javascript facebook react-native textinput

我正在尝试创建受密码保护的屏幕。屏幕将使用4个数字输入作为密码。

我这样做的方法是创建一个TextInput组件并在我的主屏幕中调用它4次。

我遇到的问题是,当我键入前一个TextInput的值时,TextInputs不会关注下一个。

我在所有PasscodeTextInput组件中都使用了refs(我已经被告知这是一种遗留方法,但我不知道其他任何方式,唉)。

试过这个方法(没有创建我自己的组件),也没有运气。 METHOD

Image

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

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

更新1

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

6 个答案:

答案 0 :(得分:9)

TextInput有一个defaultProp,可以在安装组件后对焦。

  

<强> 自动对焦

如果为true,则将输入聚焦在componentDidMount上,默认值为false。有关更多信息,请阅读相关的Docs

更新

componentDidUpdate之后,它无法正常工作。在这种情况下,可以使用ref以编程方式进行聚焦。

答案 1 :(得分:4)

我们采用不同的方法处理这种风格的屏幕。

而不是管理4个单独的TextInput并处理每个TextInput的焦点导航(当用户删除一个字符时再返回),我们在屏幕上有一个TextInput但是不可见(即.xpx x 0px)宽有焦点,maxLength和键盘配置等。

此TextInput接收来自用户的输入,但实际上看不到,因为每输入一个字符,我们将输入的文本渲染为一系列简单的视图/文本元素,其风格与上面的屏幕非常相似。

这种方法对我们来说效果很好,无需管理下一步&#39;或者之前的&#39; TextInput将重点放在。

之后

答案 2 :(得分:2)

你可以像Jason所说的那样使用焦点方法onChangeText,除此之外,添加maxLength={1}可以让你立即跳转到下一个输入,而无需检查添加的内容。 (只是注意到它的已弃用,但这仍然是我解决问题的方法,并且应该在v0.36之前完成,并且link解释了如何更新已弃用的函数。)< / p>

  <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()
   }}
  />
  ...

请注意我对refs的使用也已弃用,但我刚刚复制了代码,因为我可以保证你当时正在使用(希望现在也可以使用)。

最后,此类实现的主要问题是,一旦您尝试使用退格键移除数字,您的焦点将跳转到下一个,从而导致严重的UX问题。但是,您可以侦听退格键输入并执行不同的操作,而不是专注于下一个输入。因此,如果您选择使用此类实施,我将在此处留下link以供您进一步调查。

以前描述过问题的Hacky解决方案:如果您在执行任何操作之前检查onChangeText道具中输入了什么,如果值为数字,您可以跳转到下一个输入,否则(那是退格),跳回来。 (刚想出这个想法,我还没试过。)

答案 3 :(得分:1)

我认为问题在于onSubmitEditing是在你点击&#34;返回&#34;或者&#34;输入&#34;常规键盘上的按键...键盘上没有其中一个按钮。

假设您希望每个输入只有一个字符,您可以查看onChangeText,然后检查文本是否长度为1,如果长度确实为1则调用焦点。

答案 4 :(得分:0)

    <TextInput 
    ref={input => {
          this.nameOrId = input;
        }}
    />



    <TouchableOpacity
      onPress={()=>{
        this.nameOrId.focus()
      }}
     >
      <Text>Click</Text>
    </TouchableOpacity>

答案 5 :(得分:0)

我用这个代码解决: const 验证代码:React.FC = ({ pass, onFinish }) => {

      const inputsRef = useRef<Input[] | null[]>([]);
      const [active, setActive] = useState<number>(0);

      const onKeyPress = ({ nativeEvent }: 
      NativeSyntheticEvent<TextInputKeyPressEventData>) => {
       if (nativeEvent.key === "Backspace") {
        if (active !== 0) {
          inputsRef.current[active - 1]?.focus();
          return setActive(active - 1);
        }
       } else {
          inputsRef.current[active + 1]?.focus();
          return setActive(active + 1);
       }
      return null;
     };

   return (
    <View style={styles.container}>
      <StyledInput
        onKeyPress={onKeyPress}
        autoFocus={active === 0}
        ref={(r) => {
          inputsRef.current[0] = r;
        }}
      />
      <StyledInput
        onKeyPress={onKeyPress}
        autoFocus={active === 1}
        ref={(r) => {
          inputsRef.current[1] = r;
        }}
      />
      <StyledInput
        onKeyPress={onKeyPress}
        autoFocus={active === 2}
        ref={(r) => {
          inputsRef.current[2] = r;
        }}
      />
      <StyledInput
        onKeyPress={onKeyPress}
        autoFocus={active === 3}
        ref={(r) => {
          inputsRef.current[3] = r;
        }}
      />
    </View>
 );
};

export default VerifyCode;

我在所有输入中放了一个 ref,当 onKeyPress 触发时,该函数验证是否必须返回或转到下一个输入