React Native:按下“下一步”键盘按钮后如何选择下一个TextInput?


199

我定义了两个TextInput字段,如下所示:

<TextInput 
   style = {styles.titleInput}
   returnKeyType = {"next"}
   autoFocus = {true}
   placeholder = "Title" />
<TextInput
   style = {styles.descriptionInput}          
   multiline = {true}
   maxLength = {200}
   placeholder = "Description" />

但是在按下键盘上的“下一步”按钮后,我的本机应用程序没有跳到第二个TextInput字段。我该如何实现?

谢谢!


米奇的答案(目前是第3个答案)对我适用于v0.42。
劳伦斯

对于使用React v16.8.0或更高版本的人员,我建议底部使用@Eli Johnson提供的答案。React已弃用ref以下解决方案中提供的许多用途 。
thedeg123

Answers:


330

将第二个TextInput焦点,当以前TextInputonSubmitEditing被触发。

试试这个

  1. 将引用添加到第二个TextInput
    ref={(input) => { this.secondTextInput = input; }}

  2. 将焦点函数绑定到第一个TextInput的onSubmitEditing事件。
    onSubmitEditing={() => { this.secondTextInput.focus(); }}

  3. 切记将blurOnSubmit设置为false,以防止键盘闪烁。
    blurOnSubmit={false}

完成后,它应该看起来像这样。

<TextInput
    placeholder="FirstTextInput"
    returnKeyType="next"
    onSubmitEditing={() => { this.secondTextInput.focus(); }}
    blurOnSubmit={false}
/>

<TextInput
    ref={(input) => { this.secondTextInput = input; }}
    placeholder="secondTextInput"
/>

53
值得一提的是,该onSubmitEditing回调在blur事件之后被调用。因此,如果立即关注下一个元素,键盘可能会发疯。因此,设置blurOnSubmit={false}表单中的所有元素但留在true最后一个元素上可能会有所帮助,以允许“完成”按钮模糊最后一个输入。
e1dar

9
从v0.36开始,这不再起作用。在组件上没有“聚焦”的方法。我们现在应该怎么做?
米奇

4
@Mitch在0.40.0上工作正常。您所运行的版本中可能存在错误。
vikki '17

3
使用RN 0.49,添加blurOnSubmit={false}了防止键盘闪烁的功能,导致此功能停止工作,谁知道这是怎么回事?
nabil伦敦

13
对于无法完成focus工作的任何人,请确保您没有对TextInput组件使用包装器。如果您有一个自动CustomTextInput包装的say 组件,则TextInput需要TextInput对该组件实施模糊和聚焦方法,以使其按预期工作。
Cihad Turhan

65

您可以在不使用refs的情况下执行此操作。此方法是首选方法,因为ref可能会导致代码易碎。该阵营文档奉劝如果可能的话寻找其他的解决方案:

如果您尚未使用React编写多个应用程序,那么您的第一个倾向通常是尝试使用引用在应用程序中“使事情发生”。如果是这种情况,请花点时间仔细考虑一下在组件层次结构中应在何处拥有状态。通常,很明显,“拥有”该状态的适当位置在层次结构中处于较高级别。将状态放在那里通常消除了使用引用“使事情成真”的任何愿望–相反,数据流通常可以实现您的目标。

相反,我们将使用状态变量来聚焦第二个输入字段。

  1. 将一个状态变量作为道具传递给DescriptionInput

    initialState() {
      return {
        focusDescriptionInput: false,
      };
    }
  2. 定义将此状态变量设置为true的处理程序方法:

    handleTitleInputSubmit() {
      this.setState(focusDescriptionInput: true);
    }
  3. 在提交/点击输入/下一步后TitleInput,我们会打电话handleTitleInputSubmit。这将设置focusDescriptionInput为true。

    <TextInput 
       style = {styles.titleInput}
       returnKeyType = {"next"}
       autoFocus = {true}
       placeholder = "Title" 
       onSubmitEditing={this.handleTitleInputSubmit}
    />
  4. DescriptionInputfocusprop设置为我们的focusDescriptionInput状态变量。因此,当focusDescriptionInput更改时(在步骤3中),DescriptionInput将使用重新渲染focus={true}

    <TextInput
       style = {styles.descriptionInput}          
       multiline = {true}
       maxLength = {200}
       placeholder = "Description" 
       focus={this.state.focusDescriptionInput}
    />

这是避免使用ref的好方法,因为ref可能导致更脆弱的代码:)

编辑:h / t @LaneRettig指出您需要使用一些添加的props和方法包装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(); 
    }

2
@LaneRettig您完全正确-感谢您指出这一点。我们用一些附加的道具和方法包装RN TextInput -请查看答案的底部有这些附加的内容,并告诉我您是否还有其他问题!
Stedman Blake

4
凉。您应该将此作为PR提交给RN。令我惊讶的是,该功能尚未被立即使用。
Lane Rettig

8
如果您在键盘上单击“下一步”,然后直接在第一个输入上单击该怎么办?焦点回到第二点,那是该解决方案的不好经验
Piotr

3
我不喜欢这种解决方案,尤其是因为它无法很好地扩展5-6元素的较长形式,在这种情况下,您需要每个元素的状态布尔值并对其进行相应的管理。
davidgoli

9
有趣的是,文档还指出:“裁判有一些很好的用例:管理焦点,文本选择或媒体播放...”因此,在这种情况下,使用裁判来集中文本输入将是该工具的有效用法。
诺亚·艾伦

26

从React Native 0.36开始,focus()不再支持在文本输入节点上进行调用(如其他一些答案所建议)。相反,您可以使用TextInputStateReact 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" />
...

1
效果很棒,但是如果有人使用redux-form应该做这样的事情。<Field ... onSubmitEditing={() => focusTextInput(this._password)} />和ref应该是这样的<Field ... withRef refName={e => this._password = e}/>
tarkanlar

1
我不得不使用'onSubmitEditing'来完成这项工作,但是仍然是一个很好的解决方案。
亚当·贾基拉

3
在0.42中效果很好。
劳伦斯

1
@tarkanlar您可以共享该解决方案的代码段吗?使用redux形式的Field时,我似乎无法集中精力,仅使用TextInput即可,很好
jasan

2
calling focus() on a text input node isn't supported any more=>粗体声明,来源?调用focus()工作正常v0.49.5 + TextInputState未记录的同时focus(),并blur()提到:facebook.github.io/react-native/releases/next/docs/...
tanguy_k

21

我创建了一个小型库来执行此操作,除了替换包装视图和导入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/


实现此结果的绝佳模式。从易用性的角度来看,应该是最佳答案。看起来我可以轻松地编辑自定义的FormInput(TextInput扩展名)以仍然可以与您的Form输入一起使用。介意我是否将其包含在您的答案中,以供进一步举例说明?
杰克·罗布森,

当然!我知道...我在其他与此相关的热门帖子上发布了此内容,但遇到了重复的麻烦。只是想提供帮助,因为我知道这个问题有多烦人!!
zackify

如果您彼此紧接着有一堆TextInput,那么这很好,但是如果您想在它们之间添加样式,它就会崩溃。谢谢您的贡献。
GenericJam

随意调整代码。我确定您可以采用一种方法来跳过不是文本输入的元素。应该不难做。
zackify

1
这不适用于生产RN@0.47.2
Phil Andrews

17

以为我会用一个功能组件分享我的解决办法......“ ”没有必要!

React 16.12.0和React Native 0.61.5

这是我的组件的一个示例:

import React, { useRef } from 'react'
...


const MyFormComponent = () => {

  const ref_input2 = useRef();
  const ref_input3 = useRef();

  return (
    <>
      <TextInput
        placeholder="Input1"
        autoFocus={true}
        returnKeyType="next"
        onSubmitEditing={() => ref_input2.current.focus()}
      />
      <TextInput
        placeholder="Input2"
        returnKeyType="next"
        onSubmitEditing={() => ref_input3.current.focus()}
        ref={ref_input2}
      />
      <TextInput
        placeholder="Input3"
        ref={ref_input3}
      />
    </>
  )
}

我不知道,希望这对某人有帮助=)


1
不工作。未定义不是对象评估_this2.ref_input2.current,请帮助
DEEP ADHIYA

您能否提供更完整的代码示例?
伊莱·约翰逊

2
在功能组件中使用useRef可能比createRef更好
hyuk lee

@hyuklee先生,您的确是正确的,我已经更新了...感谢您的注意!干杯!
伊莱·约翰逊

对于那些喜欢紧跟最新的反应更新的人来说,这就是答案。
Yokhen

13

使用react-native 0.45.1时,在按用户名TextInput上的返回键后,尝试将焦点设置在密码TextInput上也遇到了问题。

在SO上尝试了大多数最受好评的解决方案之后,我在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>
        )
    }
}

您救了我的命
:)

1
您仅已重命名refinputRef...您可以删除整个自定义组件,并且只要恢复使用就可以继续使用第二个代码块ref
Jason Tolliver,

9

对我而言,RN 0.50.3可以通过以下方式实现:

<TextInput 
  autoFocus={true} 
  onSubmitEditing={() => {this.PasswordInputRef._root.focus()}} 
/>

<TextInput ref={input => {this.PasswordInputRef = input}} />

您必须看到this.PasswordInputRef。_root .focus()


1
这是特定于“本地基础”的内容
Developia

8

如果您碰巧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


如何调用onSubmitEditing函数?例如:我想在用户按下最后一个文本输入的returnkeytype'done'时调用login()函数。
chetan

7

这就是我实现它的方式。下面的示例使用了React 16.3中引入的React.createRef()API。

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

我认为这会对您有所帮助。


.current的目的是什么?
亚当·卡兹

5

我的场景是<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} ... />);     
      } 
   }

和瞧。一切恢复正常。希望这可以帮助


4

在React Native的GitHub问题上尝试此解决方案。

https://github.com/facebook/react-native/pull/2149#issuecomment-129262565

您需要为TextInput组件使用ref属性。
然后,您需要创建一个在onSubmitEditing道具上调用的函数,该函数将焦点移到第二个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>
        );
    }
});

请在您的答案中包含链接中的相关信息。
Wes Foster 2015年

请记住,字符串引用可能会被弃用,因此该解决方案将来可能无法使用:“ ...尽管字符串引用不被弃用,但它们被认为是旧有的,将来可能会被弃用。回调引用是首选。” - facebook.github.io/react/docs/more-about-refs.html
尤拉

1
从v0.36开始,这不再起作用。在组件上没有“聚焦”的方法。我们现在应该怎么做?您可以更新答案吗?
米奇

@Mitch不知道它是否回到0.39.2,但是现在可以正常工作。
Eldelshell '16

4

使用回调引用而不是旧式字符串引用:

<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}
/>

1
由于焦点方法已从TextInput中删除,因此无法使用。
雅各布·劳里岑

3
<TextInput 
    keyboardType="email-address"
    placeholder="Email"
    returnKeyType="next"
    ref="email"
    onSubmitEditing={() => this.focusTextInput(this.refs.password)}
    blurOnSubmit={false}
 />
<TextInput
    ref="password"
    placeholder="Password" 
    secureTextEntry={true} />

并添加方法onSubmitEditing={() => this.focusTextInput(this.refs.password)}如下:

private focusTextInput(node: any) {
    node.focus();
}

2

为了使您接受的解决方案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}/>
}

1
嗨,@ Eldelshell,我想实现同样的目标,但无法整理您的样本,您介意向我们提示一下吗?
Seeliang 2013年

我认为这应该是正确的答案。我遵循这一点,并且有效。
张大卫

这些都在同一个文件中吗?
MoralCode '18

2

在您的组件中:

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'输入中引用

并在您的文本输入中像这样

<TextInput
         onSubmitEditing={() => {
                          this.focusNextField('two');
                          }}
         returnKeyType="next"
         blurOnSubmit={false}/>


<TextInput      
         ref={input => {
              this.inputs['two'] = input;
                        }}/>

2
<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%', }} />

并添加方法

focusNextField(nextField) {
    this.refs[nextField].focus();
}

非常整洁的方法。
Siraj Alam

1
旧答案,但是有人知道是否可以在功能性(无状态)组件中访问此答案中的所有引用?
道格拉斯·施密特

1

有一种方法来捕捉选项卡TextInput。这很古怪,但总比没有好

定义一个onChangeText将新输入值与旧输入值进行比较的处理程序,并检查\t。如果找到一个,则按@boredgames所示前进字段

假设变量username包含用户名的值,并setUsername分派操作以在存储中(组件状态,redux存储等)对其进行更改,请执行以下操作:

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

使用物理键盘,这对我不起作用。onChangeText事件不会在标签上触发。
Bufke '16

0

这里的输入溶液的试剂溶液具有:focus属性。

只要此prop设置为true,该字段便会被聚焦,并且如果此参数为false则将不具有焦点。

不幸的是,该组件需要定义一个: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


@Bap-这是Clojurescript。试剂是对React的绑定。如果您很好奇,那么如果您急于升级,这将是React的最佳选择,因为通常只有swap!atom类型的显式调用才能进行状态更新。根据文档,这用于绑定到React:“使用原子的任何组件都会在其值更改时自动重新渲染。” reagent-project.github.io
德尔

0

如果您将NativeBase用作UI组件,则可以使用此示例

<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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.