React Native: Как выбрать следующий TextInput после нажатия клавиши "Next"?
Я определил два поля TextInput следующим образом:
<TextInput
style = {styles.titleInput}
returnKeyType = {"next"}
autoFocus = {true}
placeholder = "Title" />
<TextInput
style = {styles.descriptionInput}
multiline = {true}
maxLength = {200}
placeholder = "Description" />
Но после нажатия "следующей" кнопки на моей клавиатуре, мое приложение, зависящее от реакции, не перепрыгивает во второе поле TextInput. Как я могу это достичь?
Спасибо!
Ответы
Ответ 1
Установите второй фокус TextInput
, когда срабатывает предыдущий TextInput
onSubmitEditing
.
Попробуй это
-
Добавление ссылки на второй TextInput
ref={(input) => { this.secondTextInput = input; }}
-
Привязать функцию фокуса к первому событию TextInput onSubmitEditing.
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"
/>
Ответ 2
Вы можете сделать это без использования ссылок. Такой подход является предпочтительным, поскольку ref может привести к хрупкому коду. React docs советуют находить другие решения там, где это возможно:
Если вы не запрограммировали несколько приложений с помощью React, ваш первый склонность, как правило, будет пытаться использовать refs для "создания вещей" произойдет "в вашем приложении. Если это так, сделайте минутку и подумайте больше критически о том, где государство должно принадлежать компоненту иерархия. Часто становится ясно, что надлежащее место для" состояние находится на более высоком уровне в иерархии. Размещение там штата часто устраняет любое желание использовать refs для "совершения вещей" - вместо этого поток данных обычно достигнет вашей цели.
Вместо этого мы будем использовать переменную состояния, чтобы сфокусировать второе поле ввода.
-
Добавьте переменную состояния, которую мы передадим в качестве опоры для DescriptionInput
:
initialState() {
return {
focusDescriptionInput: false,
};
}
-
Определите метод обработчика, который установит эту переменную состояния в значение true:
handleTitleInputSubmit() {
this.setState(focusDescriptionInput: true);
}
-
При отправке/нажатии enter/next на TitleInput
, мы назовем handleTitleInputSubmit
. Это установит focusDescriptionInput
в значение true.
<TextInput
style = {styles.titleInput}
returnKeyType = {"next"}
autoFocus = {true}
placeholder = "Title"
onSubmitEditing={this.handleTitleInputSubmit}
/>
-
DescriptionInput
focus
prop установлен в нашу переменную состояния focusDescriptionInput
. Таким образом, когда focusDescriptionInput
изменяется (на шаге 3), DescriptionInput
будет повторно отображать с помощью focus={true}
.
<TextInput
style = {styles.descriptionInput}
multiline = {true}
maxLength = {200}
placeholder = "Description"
focus={this.state.focusDescriptionInput}
/>
Это хороший способ избежать использования ссылок, поскольку 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();
}
Ответ 3
Как и в случае с React Native 0.36, вызов focus()
(как предложено в нескольких других ответах) на ввод текста node больше не поддерживается. Вместо этого вы можете использовать модуль 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" />
...
Ответ 4
Я создал небольшую библиотеку, которая делает это, никакое изменение кода не требуется, кроме замены вашего вида упаковки и импорта 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.codes/autofocus-inputs-in-react-native/
Ответ 5
Использование response-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>
)
}
}
Ответ 6
Для меня на RN 0.50.3 это возможно следующим образом:
<TextInput
autoFocus={true}
onSubmitEditing={() => {this.PasswordInputRef._root.focus()}}
/>
<TextInput ref={input => {this.PasswordInputRef = input}} />
Вы должны увидеть это .PasswordInputRef. _root.focus()
Ответ 7
Если вы используете 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)
Ответ 8
Это способ, которым я достиг этого. А в приведенном ниже примере используется API React.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>
);
}
}
Я думаю, что это поможет вам.
Ответ 9
Используя обратные вызовы вместо legacy строка refs:
<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}
/>
Ответ 10
Попробуйте это решение для проблем React Native GitHub.
https://github.com/facebook/react-native/pull/2149#issuecomment-129262565
Вам нужно использовать ref prop для компонента TextInput.
Затем вам нужно создать функцию, которая вызывается в onSubmitEditing, которая перемещает фокус на второй 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>
);
}
});
Ответ 11
Мой сценарий - <CustomBoladonesTextInput/>, заключающий в себе RN <TextInput/>.
Я решил эту проблему следующим образом:
Моя форма выглядит так:
<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} ... />);
}
}
И вуаля. Все снова работает снова. Надеюсь это поможет
Ответ 12
Для принятого решения для работы, если ваш 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}/>
}
Ответ 13
Существует способ захвата вкладок в TextInput
. Это взломанно, но лучше ничего.
Определите обработчик onChangeText
, который сравнивает новое входное значение со старым, проверяя . Если он найден, перейдите в поле, как показано @boredgames
Предполагая, что переменная username
содержит значение для имени пользователя и setUsername
отправляет действие для его изменения в хранилище (состояние компонента, хранилище редукции и т.д.), выполните следующие действия:
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} />
)
}
}
Ответ 14
в вашем компоненте:
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 в NativeBase'Library 'Input
и в ваших текстовых вводах, подобных этому
<TextInput
onSubmitEditing={() => {
this.focusNextField('two');
}}
returnKeyType="next"
blurOnSubmit={false}/>
<TextInput
ref={input => {
this.inputs['two'] = input;
}}/>
Ответ 15
Здесь представлено решение для входного компонента, имеющего свойство: focus.
Поле будет сфокусировано до тех пор, пока значение этой опоры будет установлено в true и не будет иметь фокус, пока это ложно.
К сожалению, этот компонент должен иметь: ref определенный, я не мог найти другой способ вызвать .focus() на нем. Я рад предложениям.
(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
Ответ 16
Если вы используете NativeBase в качестве компонентов пользовательского интерфейса, вы можете использовать этот пример
<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>'''
Ответ 17
Добавьте метод к вашему пользовательскому компоненту, который будет возвращать ссылку на TextInput. Получите ссылку на ваш пользовательский компонент и вызовите метод для этой ссылки.
getInnerRef = () => this.ref;
render() {
return (
<View>
<TextInput
{...this.props}
ref={(r) => this.ref = r}
/>
</View>
)
}
render() {
return (
<View>
<CustomTextInput
onSubmitEditing={() => this.refInput.getInnerRef().focus()}
/>
<CustomTextInput
{...this.props}
ref={(r) => this.refInput = r}
/>
</View>
)
}
Оригинал ответил basbase здесь.