web-dev-qa-db-ja.com

反応ネイティブで次のTextInputをオートフォーカスする方法

パスコードで保護された画面を作成しようとしています。画面では、パスコードとして4つの数値入力を使用します。

これを行う方法は、TextInputコンポーネントを作成し、メイン画面で4回呼び出します。

私が抱えている問題は、前のTextInputの値を入力するときに、TextInputが次の問題にフォーカスしないことです。

すべてのPasscodeTextInputコンポーネントにrefを使用しています(これはレガシーメソッドであることが通知されていますが、他の方法はわかりません)。

このメソッドを試してみましたが(自分のコンポーネントを作成せずに)、運もありませんでした。[ 〜#〜]メソッド[〜#〜]

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);
8
J.Doe

ref特別なプロパティ の1つであるため、refを_<TextInput>_に転送することはできません。したがって、_this.refs.passcode2_を呼び出すと、代わりに_<PasscodeTextInput>_が返されます。

_<TextInput>_からrefを取得するには、次のように変更してください。

PasscodeTextInput.js

_const PasscodeTextInput = ({ inputRef, ... }) => {

  ...

  return (
    <View>
      <TextInput
        ref={(r) => { inputRef && inputRef(r) }}
        ...
      />
    </View>
    ...
  );
}
_

次に、inputRefから_<PasscodeTextInput>_を変数に割り当て、focus()を使用してフォーカスを切り替えます(RN _0.41.2_以降は非推奨ではありません)。

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 }} />
);
_

PS:event && this.passcode2.focus()は、古いパスコードをクリアして新しいパスコードを入力しようとしたときにフォーカスが切り替わらないようにします。

6
max23_

コンポーネントがマウントされた後にフォーカスできるTextInputのdefaultPropがあります。

autoFocus

Trueの場合、入力をcomponentDidMountにフォーカスします。デフォルト値はfalseです。詳細については、関連する Docs を参照してください。

更新

componentDidUpdate以降は正常に動作しません。その場合、refを使用してプログラムでフォーカスできます。

11
Mukundhan

この画面スタイルは別の方法で処理しました。

4つの個別のTextInputを管理し、それぞれのフォーカスのナビゲーションを処理するのではなく(ユーザーが文字を削除したときに再び戻る)、画面に単一のTextInputがありますが、フォーカスがある(つまり0px x 0px)幅は表示されません。 、maxLength、キーボード構成など.

このTextInputはユーザーから入力を受け取りますが、実際には表示されません。入力されたテキストを一連の単純なView/Text要素としてレンダリングし、上記の画面によく似たスタイルを設定します。

このアプローチは私たちにとってはうまく機能し、「次の」または「前の」TextInputの次に何を集中するかを管理する必要はありませんでした。

4
crafterm

Jasonが述べたように、フォーカスメソッドonChangeTextに加えて、maxLength={1}を使用すると、何が追加されたかを確認せずに、すぐに次の入力にジャンプできます。 ((deprecatedに気付いたばかりですが、これは私が問題を解決した方法であり、v0.36まで正常に動作するはずです) link は、非推奨の関数を更新する方法を説明しています。

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

私のrefの使用も非推奨ですが、その時点で機能していたことを保証できるので、コードをコピーしたところです(うまくいけば今も機能します)。

最後に、このタイプの実装の主な問題はです。バックスペースを含む数値を削除しようとすると、フォーカスが次の数値にジャンプし、深刻なUXが発生します。問題。ただし、バックスペースキーの入力をリッスンして、次の入力に集中する代わりに別のことを実行できます。したがって、このタイプの実装を使用することを選択したかどうかをさらに調査するために、ここに link を残しておきます。

前述の問題のハッキーな解決策:何かを行う前にonChangeTextプロップに入力された内容を確認すると、次の入力にジャンプできますvalueはnumberであり、それ以外の場合(つまり、バックスペース)、ジャンプして戻ります。 (このアイデアを思いついただけで、まだ試していません。)

2
eden

問題は、onSubmitEditingが通常のキーボードの「Return」または「Enter」キーを押したときだと思います...キーパッドにこれらのボタンの1つがありません。

各入力に1文字のみを含める場合、onChangeTextを見て、テキストの長さが1かどうかを確認し、長さが本当に1の場合はfocusを呼び出します。

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



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