React Native: как выбрать следующий TextInput после нажатия кнопки клавиатуры "далее"?
Я определил два поля TextInput следующим образом:
<TextInput
style = {styles.titleInput}
returnKeyType = {"next"}
autoFocus = {true}
placeholder = "Title" />
<TextInput
style = {styles.descriptionInput}
multiline = {true}
maxLength = {200}
placeholder = "Description" />
но после нажатия кнопки "Далее" на моей клавиатуре мое приложение react-native не переходит ко второму полю TextInput. Как я могу этого достичь?
спасибо!
15 ответов
второй TextInput
фокус, когда предыдущий TextInput
' s onSubmitEditing
срабатывает.
попробуй такое
добавление ссылки на второй TextInput
ref={(input) => { this.secondTextInput = input; }}
привязать функцию фокусировки к первый TextInputonSubmitEditing событие.
onSubmitEditing={() => { this.secondTextInput.focus(); }}
Не забудьте установить blurOnSubmit в false, чтобы предотвратить клавиатуру колеблющийся.
blurOnSubmit={false}
когда все сделано, это должно выглядеть так.
<TextInput
placeholder = "FirstTextInput"
returnKeyType = { "next" }
onSubmitEditing={() => { this.secondTextInput.focus(); }}
blurOnSubmit={false}
/>
<TextInput
ref={(input) => { this.secondTextInput = input; }}
placeholder = "secondTextInput"
/>
вы можете сделать это без использования refs. Этот подход является предпочтительным, так как refs может привести к хрупкий код. The React docs советую найти другие решения, где это возможно:
если вы не запрограммировали несколько приложений с React, ваш первый склонность, как правило, будет пытаться использовать refs для " создания вещей произошло" в вашем приложении. Если это так, найдите момент и подумайте больше критически о том, где государство должно быть в компоненте иерархия. Часто становится ясно, что правильное место ,чтобы "владеть", что состояние находится на более высоком уровне иерархии. Размещение государства там часто исключает любое желание использовать refs для того чтобы "сделать вещи случиться" – вместо этого поток данных обычно достигает вашей цели.
вместо этого мы будем использовать переменную состояния для фокусировки второго поля ввода.
-
добавьте переменную состояния, которую мы передадим в качестве опоры
DescriptionInput
:initialState() { return { focusDescriptionInput: false, }; }
-
определите метод обработчика, который установит для этой переменной состояния значение true:
handleTitleInputSubmit() { this.setState(focusDescriptionInput: true); }
-
после отправки / нажатия enter / next на
TitleInput
, мы будем называтьhandleTitleInputSubmit
. Это будет setfocusDescriptionInput
значение true.<TextInput style = {styles.titleInput} returnKeyType = {"next"} autoFocus = {true} placeholder = "Title" onSubmitEditing={this.handleTitleInputSubmit} />
-
DescriptionInput
' sfocus
prop установлен на нашfocusDescriptionInput
переменной состояния. Итак, когдаfocusDescriptionInput
изменения (в шаге 3),DescriptionInput
будет повторно визуализировать сfocus={true}
.<TextInput style = {styles.descriptionInput} multiline = {true} maxLength = {200} placeholder = "Description" focus={this.state.focusDescriptionInput} />
это хороший способ избежать использования refs, так как refs может привести к более хрупкому коду:)
EDIT: h / t to @LaneRettig для указания на то, что вам нужно будет обернуть React Native TextInput с некоторыми добавленными реквизитами и методами, чтобы заставить его ответить на focus
:
// Props:
static propTypes = {
focus: PropTypes.bool,
}
static defaultProps = {
focus: false,
}
// Methods:
focus() {
this._component.focus();
}
componentWillReceiveProps(nextProps) {
const {focus} = nextProps;
focus && this.focus();
}
по состоянию на React Native 0.36, вызывая focus()
(как предложено в нескольких других ответах) на узле ввода текста больше не поддерживается. Вместо этого, вы можете использовать TextInputState
модуль от React Native. Я создал следующий вспомогательный модуль, чтобы сделать это проще:
// 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)
}
}
вы можете, тогда, вызвать focusTextInput
функция на любом "ref"TextInput
. Например:
...
<TextInput onSubmit={() => focusTextInput(this.refs.inputB)} />
<TextInput ref="inputB" />
...
Я создал небольшую библиотеку, которая делает это, никаких изменений кода не требуется, кроме замены вашего представления обертки и импорта 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
подробно объяснено здесь:https://zach.коды / автофокус-входы-в-реагировать-родной/
используя react-native 0.45.1 я также столкнулся с проблемами, пытаясь установить фокус на TextInput пароля после нажатия клавиши возврата на TextInput имени пользователя.
после того, как я попробовал большинство лучших решений здесь, поэтому я нашел решение на github, которое удовлетворило мои потребности: https://github.com/shoutem/ui/issues/44#issuecomment-290724642
в итоге:
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)}
/>
);
}
}
и затем я использую его так:
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>
)
}
}
если вы используете tcomb-form-native
как я, Вы тоже можете это сделать. Вот трюк: вместо реквизита TextInput
напрямую, Вы делаете это через options
. Вы можете ссылаться на поля формы как:
this.refs.form.getComponent('password').refs.input.focus()
так что конечный продукт выглядит примерно так:
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>
);
},
});
(кредит remcoanker для размещения идеи здесь:https://github.com/gcanti/tcomb-form-native/issues/96)
для меня на RN 0.50.3 это возможно таким образом:
<TextInput
autoFocus={true}
onSubmitEditing={() => {this.PasswordInputRef._root.focus()}}
/>
<TextInput ref={input => {this.PasswordInputRef = input}} />
вы должны это увидеть.PasswordInputRef.строка _root.focus ()
попробуйте это решение на проблемах GitHub React Native.
https://github.com/facebook/react-native/pull/2149#issuecomment-129262565
вам нужно использовать ref prop для компонента TextInput.
Затем вам нужно создать функцию, которая вызывается onsubmitediting prop, которая перемещает фокус на второй TextInput ref.
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>
);
}
});
использование ссылок обратного вызова вместо наследие строку ссылки:
<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}
/>
для принятого решения работать, если ваш TextInput
находится внутри другого компонента, вам нужно будет "поп" ссылку из ref
к родительскому контейнеру.
// 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}/>
}
вот как я этого достиг. И пример ниже использовал React.API createRef () представлен в 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>
);
}
}
Я думаю, это поможет вам.
есть способ захватить вкладки на TextInput
. Это hacky, но лучше, чем ничего.
определение onChangeText
обработчик, который сравнивает новое входное значение со старым, проверка \t
. Если он найден, продвиньте поле, как показано @boredgames
предполагая, что переменная username
содержит значение для имени пользователя и setUsername
отправляет действие, чтобы изменить его в магазине (состояние компонента, redux store и т. д.), Что-то сделать вот так:
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} />
)
}
}
в компоненте:
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();
}
Примечание: я использовал ._root
потому что это ссылка на TextInput в 'Library NativeBase'
и в ваших текстовых вводах, как это
<TextInput
onSubmitEditing={() => {
this.focusNextField('two');
}}
returnKeyType="next"
blurOnSubmit={false}/>
<TextInput
ref={input => {
this.inputs['two'] = input;
}}/>
мой сценарий обертывание RN .
Я решил эту проблему следующим образом:
моя форма выглядит так:
<CustomBoladonesTextInput
onSubmitEditing={() => this.customInput2.refs.innerTextInput2.focus()}
returnKeyType="next"
... />
<CustomBoladonesTextInput
ref={ref => this.customInput2 = ref}
refInner="innerTextInput2"
... />
в определении компонента CustomBoladonesTextInput я передаю поле refField во внутреннюю опору ref следующим образом:
export default class CustomBoladonesTextInput extends React.Component {
render() {
return (< TextInput ref={this.props.refInner} ... />);
}
}
и вуаля. Все снова работает. Надеюсь, это поможет
здесь решение реагента для входного компонента, имеющего свойство: focus.
поле будет сфокусировано до тех пор, пока эта опора установлена в true и не будет иметь фокуса, пока это false.
к сожалению, этот компонент должен иметь: ref определен, я не мог найти другой способ вызова .focus() on it. Я рад предложениям.
(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