J'essaie de créer un écran protégé par mot de passe. L'écran utilise 4 entrées numériques comme mot de passe.
La façon dont je fais cela est de créer un composant TextInput et de l'appeler 4 fois dans mon écran principal.
Le problème que j'ai est que les TextInputs ne se concentrent pas sur le suivant car je tape la valeur du TextInput précédent.
J'utilise des références pour tous les composants PasscodeTextInput (j'ai été informé qu'il s'agit d'une méthode héritée mais je ne connais pas d'autre moyen, hélas).
J'ai essayé cette méthode (sans créer mon propre composant), pas de chance aussi. MÉTHODE
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 };
Mise à jour 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);
Vous ne pouvez pas transmettre le ref
à <TextInput>
En utilisant cette méthode car ref
est l'un des accessoires spéciaux . Ainsi, appeler this.refs.passcode2
Vous renverra <PasscodeTextInput>
À la place.
Essayez de modifier ce qui suit pour obtenir le ref
de <TextInput>
.
PasscodeTextInput.js
const PasscodeTextInput = ({ inputRef, ... }) => {
...
return (
<View>
<TextInput
ref={(r) => { inputRef && inputRef(r) }}
...
/>
</View>
...
);
}
Ensuite, affectez le inputRef
de <PasscodeTextInput>
À une variable et utilisez focus()
pour changer de focus (il n'est pas obsolète à partir de 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 }} />
);
P.S: event && this.passcode2.focus()
empêche la mise au point lorsque vous essayez d'effacer l'ancien code d'accès et d'en saisir un nouveau.
Il existe un defaultProp pour TextInput où l'on peut se concentrer après le montage du composant.
autoFocus
Si true, concentre l'entrée sur componentDidMount, la valeur par défaut est false. pour plus d'informations, veuillez lire le Docs .
Après componentDidUpdate
cela ne fonctionnera pas correctement. Dans ce cas, on peut utiliser ref
pour se concentrer par programme.
nous avons géré ce style d'écran avec une approche différente.
Plutôt que de gérer 4 TextInputs individuels et de gérer la navigation du focus à travers chacun (puis de revenir en arrière lorsque l'utilisateur supprime un caractère), nous avons un seul TextInput à l'écran mais invisible (c.-à-d. 0px x 0px) de large qui a le focus , configuration maxLength et clavier, etc.
Ce TextInput prend l'entrée de l'utilisateur mais ne peut pas réellement être vu, car chaque caractère est tapé, nous rendons le texte entré comme une simple série d'éléments View/Text, de style très similaire à votre écran ci-dessus.
Cette approche a bien fonctionné pour nous, sans avoir besoin de gérer ce à quoi le texte suivant ou le texte précédent doit se concentrer.
Vous pouvez utiliser la méthode de mise au point onChangeText
comme l'a déclaré Jason, en plus de l'ajout de maxLength={1}
peut vous faire passer immédiatement à l'entrée suivante sans vérifier ce qui a été ajouté. (vient de remarquer que son est déconseillé , mais c'est toujours ainsi que j'ai résolu mon problème, et devrait bien fonctionner jusqu'à la v0.36, et ce lien explique comment mettre à jour la fonction obsolète).
<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()
}}
/>
...
Veuillez noter que mon utilisation des références est également obsolète, mais je viens de copier le code car je peux vous garantir que cela fonctionnait à l'époque (fonctionne avec optimisme maintenant aussi).
Enfin, le principal problème avec ce type d'implémentation est , une fois que vous essayez de supprimer un nombre avec retour arrière, votre focus passera au suivant, provoquant une grave UX problèmes. Cependant, vous pouvez écouter l'entrée de la touche de retour arrière et effectuer quelque chose de différent au lieu de vous concentrer sur l'entrée suivante. Je vais donc laisser un lien ici pour que vous puissiez approfondir si vous choisissez d'utiliser ce type d'implémentation.
Solution Hacky au problème décrit précédemment: Si vous vérifiez ce qui est entré dans onChangeText
prop avant de faire quoi que ce soit, vous pouvez passer à l'entrée suivante si le valeur est un nombre , sinon (c'est un retour arrière), sautez en arrière. (Je viens juste de trouver cette idée, je ne l'ai pas essayée.)
Je pense que le problème est que onSubmitEditing
est lorsque vous appuyez sur la touche "retour" ou "entrée" du clavier normal ... il n'y a pas un de ces boutons sur le clavier.
En supposant que vous voulez que chaque entrée ait un seul caractère, vous pouvez regarder le onChangeText
puis vérifier si le texte a une longueur 1 et appeler focus si la longueur est bien 1.
<TextInput
ref={input => {
this.nameOrId = input;
}}
/>
<TouchableOpacity
onPress={()=>{
this.nameOrId.focus()
}}
>
<Text>Click</Text>
</TouchableOpacity>