简体   繁体   English

逐步关注 TextInput 响应本机

[英]Progressively focus TextInput react native

I am currently creating a 4 digit otp (one time password) view for a react native app and i need the TextInput to progressively focus when i type a number on the previous input.我目前正在为本机应用程序创建一个 4 位 otp(一次性密码)视图,当我在上一个输入中键入数字时,我需要 TextInput 逐渐聚焦。

I have been able to make the style change (without focus) but the focus doesn't change with it and when i enter another digit the app crashes.我已经能够改变样式(没有焦点),但焦点不会随之改变,当我输入另一个数字时,应用程序崩溃。

I want it such that when i type in on the first input, the focus move to the next TextInput and so on and on the last input, it focuses on submit.我希望这样当我在第一个输入中输入时,焦点移动到下一个 TextInput 等等,在最后一个输入上,它专注于提交。

How do i go about this?我该怎么做?

Below is my code下面是我的代码

the component组件

import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, ScrollView, View, Alert, Image } from 'react-native';
import { SimpleLinearGradientButton } from '../../components/Buttons';
import { SimpleCard } from '../../components/Cards';

export default function(props) {
  const [otp, setOtp] = useState([]);
  const [isFocused, setIsFocused] = useState({ focused: true, index: 0 });

  const inputs = Array(4).fill(0);

 function renderInputs() {
    return inputs.map((input, index) => {
      return (
        <TextInput
          style={
            isFocused.focused && index === isFocused.index
              ? styles.inputFieldsFocused
              : styles.inputFields
          }
          key={index}
          keyboardType={'numeric'}
          onChange={focus}
        ></TextInput>
      );
    });
  }

  function focus(e) {
    setOtp(otp.concat(this.value));
    setIsFocused({ focused: true, index: isFocused.index + 1 });
    isFocused.index ? e.focus() : null;
  }

  return (
    <ScrollView contentContainerStyle={styles.content}>
      <View>
        <Image
          style={styles.image}
          source={require('../../../assets/images/verification.png')}
        />
      </View>
      <View>
        <Text>Verification</Text>
        <Text>
          Enter the 4 digit sent to your email address
        </Text>
      </View>
      <View>
        <SimpleCard>
          <>{renderInputs()}</>
        </SimpleCard>
        <SimpleLinearGradientButton
              title="Submit"
            />
          </View>
        </ScrollView>
      );
    }

The focus function was meant to focus the next input at that index but this doesn't seem to work but the style changes.焦点功能旨在将下一个输入集中在该索引处,但这似乎不起作用,但样式发生了变化。 How do i go about this?我该怎么做? Thanks谢谢

I suggest to use single hidden TextInput , and render digits in simple View -s, based on input's value.我建议使用单个隐藏TextInput ,并根据输入的值在简单的View -s 中呈现数字。 I see no reason to have different inputs for 4 digit code.我认为没有理由为 4 位代码设置不同的输入。

However if you need to use different inputs, you have to control their focus states in imperative way (with refs ).但是,如果您需要使用不同的输入,则必须以命令方式(使用refs )控制它们的焦点状态。 See focus() method.请参见focus()方法。 Also there are some bugs with this method ( https://github.com/facebook/react-native/issues/19366 )这种方法也有一些错误( https://github.com/facebook/react-native/issues/19366

See docs here https://facebook.github.io/react-native/docs/textinput请在此处查看文档https://facebook.github.io/react-native/docs/textinput

tl;dr Set maxLength of textInput to 1 and on onChangeText callback change to next textInput using refs and focus() tl;dr将 textInput 的 maxLength 设置为 1,并使用 refs 和 focus() 将 onChangeText 回调更改为下一个 textInput

This is a straight-forward implementation to understand easily.这是一个易于理解的直接实现。 You can reduce the code a lot better.您可以更好地减少代码。 And I guess you're supposed to implement Backspace to clear the text and go back to previous textinput.而且我猜你应该实现 Backspace 来清除文本并返回到以前的文本输入。 I used onKeyPress prop to achieve that.我使用 onKeyPress 道具来实现这一点。

import React, { Component } from 'react';
import { Text, View, StyleSheet, TextInput } from 'react-native';
import Constants from 'expo-constants';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      one: '',
      two: '',
      three: '',
      oneFocus: false,
      twoFocus: false,
      threeFocus: false,
    };
  }

  componentDidMount() {
    this.refs.one.focus();
  }

    handleChangeTextOne = (text) => {
      this.setState({ one: text }, () => { if (this.state.one) this.refs.two.focus(); });
    }
  handleChangeTextTwo = (text) => {
    this.setState({ two: text }, () => { if (this.state.two) this.refs.three.focus(); });
  }
  handleChangeTextThree = (text) => {
    this.setState({ three: text });
  }

    backspace = (id) => {
      if (id === 'two') {
        if (this.state.two) { this.setState({ two: '' }); } else if (this.state.one) { this.setState({ one: '' }); this.refs.one.focus(); }
      } else if (id === 'three') {
        if (this.state.three) { this.setState({ three: '' }); } else if (this.state.two) { this.setState({ two: '' }); this.refs.two.focus(); }
      }
    }

    render() {
      const { oneFocus, twoFocus, threeFocus } = this.state;
      const oneStyle = {
        borderBottomColor: oneFocus ? 'red' : 'black',
        borderBottomWidth: oneFocus ? 2 : 1,
      };
      const twoStyle = {
        borderBottomColor: twoFocus ? 'red' : 'black',
        borderBottomWidth: twoFocus ? 2 : 1,
      };
      const threeStyle = {
        borderBottomColor: threeFocus ? 'red' : 'black',
        borderBottomWidth: threeFocus ? 2 : 1,
      };
      return (
        <View style={styles.container}>
          <View style={styles.inputcontainer}>
            <TextInput
              ref='one'
              style={[styles.textInput, { ...oneStyle }]}
              autoCorrect={false}
              autoCapitalize='none'
              keyboardType='number-pad'
              caretHidden
              onFocus={() => this.setState({ oneFocus: true })}
              onBlur={() => this.setState({ oneFocus: false })}
              maxLength={1}
              onChangeText={(text) => { this.handleChangeTextOne(text); }}
              value={this.state.one}
            />
            <TextInput
              ref='two'
              onKeyPress={({ nativeEvent }) => (
                nativeEvent.key === 'Backspace' ? this.backspace('two') : null
              )}
              style={[styles.textInput, { ...twoStyle }]}
              autoCorrect={false}
              autoCapitalize='none'
              maxLength={1}
              onFocus={() => this.setState({ twoFocus: true })}
              onBlur={() => this.setState({ twoFocus: false })}
              caretHidden
              keyboardType='number-pad'
              onChangeText={(text) => { this.handleChangeTextTwo(text); }}
              value={this.state.two}
            />
            <TextInput
              ref='three'
              onKeyPress={({ nativeEvent }) => (
                nativeEvent.key === 'Backspace' ? this.backspace('three') : null
              )}
              style={[styles.textInput, { ...threeStyle }]}
              autoCorrect={false}
              autoCapitalize='none'
              onFocus={() => this.setState({ threeFocus: true })}
              onBlur={() => this.setState({ threeFocus: false })}
              maxLength={1}
              caretHidden
              keyboardType='number-pad'
              onChangeText={(text) => { this.handleChangeTextThree(text); }}
              value={this.state.four}
            />
          </View>
        </View>
      );
    }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
  }, 
  inputcontainer: {
    height: '5%',
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'flex-start',
    paddingHorizontal: '20%',
    marginBottom: '2%',
  }, 
  textInput: {
    fontSize: 22,
    textAlign: 'center',
    paddingVertical: 0,
    paddingHorizontal: 0,
    width: '12%',
  },
});

Run this in snack: https://snack.expo.io/@legowtham/otp-textinput-example-react-native在零食中运行: https ://snack.expo.io/@legowtham/otp-textinput-example-react-native

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM