J'ai défini deux champs TextInput comme suit:
<TextInput
style = {styles.titleInput}
returnKeyType = {"next"}
autoFocus = {true}
placeholder = "Title" />
<TextInput
style = {styles.descriptionInput}
multiline = {true}
maxLength = {200}
placeholder = "Description" />
Mais après avoir appuyé sur le bouton "Suivant" de mon clavier, mon application réagit-native ne passe pas au deuxième champ TextInput. Comment puis-je y arriver?
Merci!
Vous pouvez faire ceci sans utiliser refs. Cette approche est préférable, car les références peuvent conduire à code fragile. Les React docs conseillent de trouver d’autres solutions dans la mesure du possible:
Si vous n'avez pas programmé plusieurs applications avec React, votre premier L’inclination sera généralement d’essayer d’utiliser des références pour «faire avancer les choses arrive» dans votre application. Si tel est le cas, prenez un moment et réfléchissez davantage critique sur l'endroit où l'État devrait appartenir à la composante hiérarchie. Souvent, il devient évident que le lieu approprié pour "posséder" cela l'état est à un niveau supérieur dans la hiérarchie. Placer l'état là élimine souvent le désir d'utiliser des arbitres pour «faire avancer les choses» - Au lieu de cela, le flux de données permettra généralement d'atteindre votre objectif.
À la place, nous utiliserons une variable d'état pour focaliser le deuxième champ de saisie.
Ajoutez une variable d'état que nous allons transmettre à la variable DescriptionInput
:
initialState() {
return {
focusDescriptionInput: false,
};
}
Définissez une méthode de gestionnaire qui définira cette variable d'état sur true:
handleTitleInputSubmit() {
this.setState(focusDescriptionInput: true);
}
Lors de la soumission/en appuyant sur entrée/prochaine sur la TitleInput
, nous appellerons handleTitleInputSubmit
. Ceci définira focusDescriptionInput
sur true.
<TextInput
style = {styles.titleInput}
returnKeyType = {"next"}
autoFocus = {true}
placeholder = "Title"
onSubmitEditing={this.handleTitleInputSubmit}
/>
DescriptionInput
's focus
prop est défini sur notre variable d'état focusDescriptionInput
. Ainsi, lorsque focusDescriptionInput
change (à l'étape 3), DescriptionInput
sera restitué avec focus={true}
.
<TextInput
style = {styles.descriptionInput}
multiline = {true}
maxLength = {200}
placeholder = "Description"
focus={this.state.focusDescriptionInput}
/>
C’est un bon moyen d’éviter d’utiliser des références, car les références peuvent conduire à un code plus fragile :)
EDIT: h/t à @LaneRettig pour indiquer que vous devez encapsuler React Native TextInput avec quelques accessoires et méthodes ajoutés pour qu’il réponde à focus
:
// Props:
static propTypes = {
focus: PropTypes.bool,
}
static defaultProps = {
focus: false,
}
// Methods:
focus() {
this._component.focus();
}
componentWillReceiveProps(nextProps) {
const {focus} = nextProps;
focus && this.focus();
}
Depuis React Native 0.36, l'appel de focus()
(comme suggéré dans plusieurs autres réponses) sur un noeud de saisie de texte n'est plus pris en charge. Au lieu de cela, vous pouvez utiliser le module TextInputState
de React Native. J'ai créé le module d'aide suivant pour faciliter cela:
// TextInputManager
//
// Provides helper functions for managing the focus state of text
// inputs. This is a hack! You are supposed to be able to call
// "focus()" directly on TextInput nodes, but that doesn't seem
// to be working as of ReactNative 0.36
//
import { findNodeHandle } from 'react-native'
import TextInputState from 'react-native/lib/TextInputState'
export function focusTextInput(node) {
try {
TextInputState.focusTextInput(findNodeHandle(node))
} catch(e) {
console.log("Couldn't focus text input: ", e.message)
}
}
Vous pouvez alors appeler la fonction focusTextInput
sur n'importe quel "ref" d'une TextInput
. Par exemple:
...
<TextInput onSubmit={() => focusTextInput(this.refs.inputB)} />
<TextInput ref="inputB" />
...
J'ai créé une petite bibliothèque qui effectue cette opération. Aucune modification de code n'est nécessaire, sauf le remplacement de la vue d'habillage et l'importation de TextInput:
import { Form, TextInput } from 'react-native-autofocus'
export default () => (
<Form>
<TextInput placeholder="test" />
<TextInput placeholder="test 2" />
</Form>
)
https://github.com/zackify/react-native-autofocus
Expliqué en détail ici: https://zach.codes/autofocus-inputs-in-react-native/
À l’aide de react-native 0.45.1, j’ai également rencontré des problèmes lors de la définition du mot de passe TextInput après avoir appuyé sur la touche Entrée du nom d’utilisateur TextInput.
Après avoir essayé la plupart des solutions les mieux notées ici sur SO, j'ai trouvé sur github une solution qui répondait à mes besoins: https://github.com/shoutem/ui/issues/44#issuecomment- 290724642
Résumer:
import React, { Component } from 'react';
import { TextInput as RNTextInput } from 'react-native';
export default class TextInput extends Component {
render() {
const { props } = this;
return (
<RNTextInput
{...props}
ref={(input) => props.inputRef && props.inputRef(input)}
/>
);
}
}
Et puis je l'utilise comme ça:
import React, {Component} from 'react';
import {
View,
} from 'react-native';
import TextInput from "../../components/TextInput";
class Login extends Component {
constructor(props) {
super(props);
this.passTextInput = null
}
render() {
return (
<View style={{flex:1}}>
<TextInput
style={{flex:1}}
placeholder="Username"
onSubmitEditing={(event) => {
this.passTextInput.focus()
}}
/>
<TextInput
style={{flex:1}}
placeholder="Password"
inputRef={(input) => {
this.passTextInput = input
}}
/>
</View>
)
}
}
Si vous utilisez tcomb-form-native
comme je le suis, vous pouvez le faire aussi. Voici l’astuce: au lieu de définir directement les accessoires de TextInput
, vous le faites via options
. Vous pouvez vous référer aux champs du formulaire comme suit:
this.refs.form.getComponent('password').refs.input.focus()
Donc, le produit final ressemble à ceci:
var t = require('tcomb-form-native');
var Form = t.form.Form;
var MyForm = t.struct({
field1: t.String,
field2: t.String,
});
var MyComponent = React.createClass({
_getFormOptions () {
return {
fields: {
field1: {
returnKeyType: 'next',
onSubmitEditing: () => {this.refs.form.getComponent('field2').refs.input.focus()},
},
},
};
},
render () {
var formOptions = this._getFormOptions();
return (
<View style={styles.container}>
<Form ref="form" type={MyForm} options={formOptions}/>
</View>
);
},
});
(Nous remercions remcoanker d'avoir publié l'idée ici: https://github.com/gcanti/tcomb-form-native/issues/96 )
Pour moi sur RN 0.50.3, c'est possible de cette façon:
<TextInput
autoFocus={true}
onSubmitEditing={() => {this.PasswordInputRef._root.focus()}}
/>
<TextInput ref={input => {this.PasswordInputRef = input}} />
Vous devez voir ceci.PasswordInputRef. _root . Focus ()
C'est comme ça que je l'ai réalisé. Et l'exemple ci-dessous a utilisé l'API React.createRef () introduite dans React 16.3.
class Test extends React.Component {
constructor(props) {
super(props);
this.secondTextInputRef = React.createRef();
}
render() {
return(
<View>
<TextInput
placeholder = "FirstTextInput"
returnKeyType="next"
onSubmitEditing={() => { this.secondTextInputRef.current.focus(); }}
/>
<TextInput
ref={this.secondTextInputRef}
placeholder = "secondTextInput"
/>
</View>
);
}
}
Je crois que ceci vous aidera.
Utilisation des références de rappel au lieu des références legacy string:
<TextInput
style = {styles.titleInput}
returnKeyType = {"next"}
autoFocus = {true}
placeholder = "Title"
onSubmitEditing={() => {this.nextInput.focus()}}
/>
<TextInput
style = {styles.descriptionInput}
multiline = {true}
maxLength = {200}
placeholder = "Description"
ref={nextInput => this.nextInput = nextInput}
/>
Essayez cette solution avec les problèmes GitHub de React Native.
https://github.com/facebook/react-native/pull/2149#issuecomment-12926252565
Vous devez utiliser le prop prop pour le composant TextInput.
Ensuite, vous devez créer une fonction qui est appelée sur le prop onSubmitEditing qui déplace le focus sur la deuxième réf. TextInput.
var InputScreen = React.createClass({
_focusNextField(nextField) {
this.refs[nextField].focus()
},
render: function() {
return (
<View style={styles.container}>
<TextInput
ref='1'
style={styles.input}
placeholder='Normal'
returnKeyType='next'
blurOnSubmit={false}
onSubmitEditing={() => this._focusNextField('2')}
/>
<TextInput
ref='2'
style={styles.input}
keyboardType='email-address'
placeholder='Email Address'
returnKeyType='next'
blurOnSubmit={false}
onSubmitEditing={() => this._focusNextField('3')}
/>
<TextInput
ref='3'
style={styles.input}
keyboardType='url'
placeholder='URL'
returnKeyType='next'
blurOnSubmit={false}
onSubmitEditing={() => this._focusNextField('4')}
/>
<TextInput
ref='4'
style={styles.input}
keyboardType='numeric'
placeholder='Numeric'
blurOnSubmit={false}
onSubmitEditing={() => this._focusNextField('5')}
/>
<TextInput
ref='5'
style={styles.input}
keyboardType='numbers-and-punctuation'
placeholder='Numbers & Punctuation'
returnKeyType='done'
/>
</View>
);
}
});
Pour que la solution acceptée fonctionne si votre TextInput
se trouve dans un autre composant, vous devez "extraire" la référence de ref
au conteneur parent.
// MyComponent
render() {
<View>
<TextInput ref={(r) => this.props.onRef(r)} { ...this.props }/>
</View>
}
// MyView
render() {
<MyComponent onSubmitEditing={(evt) => this.myField2.focus()}/>
<MyComponent onRef={(r) => this.myField2 = r}/>
}
Mon scénario est <CustomBoladonesTextInput /> encapsulant un RN <TextInput /> .
J'ai résolu ce problème comme suit:
Ma forme ressemble à:
<CustomBoladonesTextInput
onSubmitEditing={() => this.customInput2.refs.innerTextInput2.focus()}
returnKeyType="next"
... />
<CustomBoladonesTextInput
ref={ref => this.customInput2 = ref}
refInner="innerTextInput2"
... />
Sur la définition du composant CustomBoladonesTextInput, je passe le refField au prop interne comme ceci:
export default class CustomBoladonesTextInput extends React.Component {
render() {
return (< TextInput ref={this.props.refInner} ... />);
}
}
Et voila. Tout retourne à nouveau. J'espère que cela t'aides
<TextInput placeholder="Nombre"
ref="1"
editable={true}
returnKeyType="next"
underlineColorAndroid={'#4DB6AC'}
blurOnSubmit={false}
value={this.state.First_Name}
onChangeText={First_Name => this.setState({ First_Name })}
onSubmitEditing={() => this.focusNextField('2')}
placeholderTextColor="#797a7a" style={{ marginBottom: 10, color: '#808080', fontSize: 15, width: '100%', }} />
<TextInput placeholder="Apellido"
ref="2"
editable={true}
returnKeyType="next"
underlineColorAndroid={'#4DB6AC'}
blurOnSubmit={false}
value={this.state.Last_Name}
onChangeText={Last_Name => this.setState({ Last_Name })}
onSubmitEditing={() => this.focusNextField('3')}
placeholderTextColor="#797a7a" style={{ marginBottom: 10, color: '#808080', fontSize: 15, width: '100%', }} />
et ajouter une méthode
focusNextField(nextField) {
this.refs[nextField].focus();
}
Il existe un moyen de capturer tabs dans une TextInput
. C'est hacky, mais mieux que rien .
Définissez un gestionnaire onChangeText
qui compare la nouvelle valeur d'entrée à l'ancienne, en recherchant un \t
. S'il en trouve un, avancez le champ comme indiqué par @boredgames
En supposant que la variable username
contient la valeur du nom d'utilisateur et que setUsername
distribue une action pour la modifier dans le magasin (état du composant, magasin redux, etc.), procédez comme suit:
function tabGuard (newValue, oldValue, callback, nextCallback) {
if (newValue.indexOf('\t') >= 0 && oldValue.indexOf('\t') === -1) {
callback(oldValue)
nextCallback()
} else {
callback(newValue)
}
}
class LoginScene {
focusNextField = (nextField) => {
this.refs[nextField].focus()
}
focusOnPassword = () => {
this.focusNextField('password')
}
handleUsernameChange = (newValue) => {
const { username } = this.props // or from wherever
const { setUsername } = this.props.actions // or from wherever
tabGuard(newValue, username, setUsername, this.focusOnPassword)
}
render () {
const { username } = this.props
return (
<TextInput ref='username'
placeholder='Username'
autoCapitalize='none'
autoCorrect={false}
autoFocus
keyboardType='email-address'
onChangeText={handleUsernameChange}
blurOnSubmit={false}
onSubmitEditing={focusOnPassword}
value={username} />
)
}
}
dans votre composant:
constructor(props) {
super(props);
this.focusNextField = this
.focusNextField
.bind(this);
// to store our input refs
this.inputs = {};
}
focusNextField(id) {
console.log("focus next input: " + id);
this
.inputs[id]
._root
.focus();
}
Note: J'ai utilisé ._root
parce que c'est une référence à TextInput dans NativeBase'Library 'Input
et dans vos entrées de texte comme ça
<TextInput
onSubmitEditing={() => {
this.focusNextField('two');
}}
returnKeyType="next"
blurOnSubmit={false}/>
<TextInput
ref={input => {
this.inputs['two'] = input;
}}/>
Si vous utilisez NativeBase en tant que composants d'interface utilisateur, vous pouvez utiliser cet exemple
<Item floatingLabel>
<Label>Title</Label>
<Input
returnKeyType = {"next"}
autoFocus = {true}
onSubmitEditing={(event) => {
this._inputDesc._root.focus();
}}
/>
</Item>
<Item floatingLabel>
<Label>Description</Label>
<Input
getRef={(c) => this._inputDesc = c}
multiline={true} style={{height: 100}} />
onSubmitEditing={(event) => { this._inputLink._root.focus(); }}
</Item>```
Voici une solution de réactif pour un composant d’entrée doté d’une propriété: focus.
Le champ sera concentré tant que cet accessoire est défini sur true et n'aura pas le focus tant que cela est faux.
Malheureusement, ce composant doit avoir un: ref défini, je n'ai pas pu trouver un autre moyen d'appeler .focus () dessus. Je suis content des suggestions.
(defn focusable-input [init-attrs]
(r/create-class
{:display-name "focusable-input"
:component-will-receive-props
(fn [this new-argv]
(let [ref-c (aget this "refs" (:ref init-attrs))
focus (:focus (ru/extract-props new-argv))
is-focused (.isFocused ref-c)]
(if focus
(when-not is-focused (.focus ref-c))
(when is-focused (.blur ref-c)))))
:reagent-render
(fn [attrs]
(let [init-focus (:focus init-attrs)
auto-focus (or (:auto-focus attrs) init-focus)
attrs (assoc attrs :auto-focus auto-focus)]
[input attrs]))}))
https://Gist.github.com/Knotschi/6f97efe89681ac149113ddec4c396cc5