如何在flutter中将焦点转移到下一个文本字段?


72

我是Flutter的新手。

我正在使用以下窗口小部件构建具有多个文本输入的表单:Form,TextFormField。出现的键盘不显示“下一个”(应将焦点转移到下一个字段)字段操作,而是“完成”操作(隐藏键盘)。

我在官方文档中寻找任何提示,没有发现直接可以做的事情。我虽然登陆了FocusNode(cookbookapi doc)。它提供了通过应用程序上的某些按钮或任何其他操作来转移焦点的机制,但我希望它位于键盘中


在flutter_gallery中也是一样。但是应该有某种机制。
严厉的Bhikadia

到目前为止,这是不可能的(请参阅github.com/flutter/flutter/issues/11344)。您在说flutter_gallery的哪一部分?
Mrigank


哦,我需要找到解决方法。我的意思是flutter_gallery也有同样的问题。
Harsh Bhikadia

Answers:


108

屏幕截图:

在此处输入图片说明


您可以不使用FocusNode或进行操作FocusScopeNode

@override
Widget build(BuildContext context) {
  final node = FocusScope.of(context);
  return Scaffold(
    body: Column(
      children: <Widget>[
        TextField(
          decoration: InputDecoration(hintText: 'TextField A'),
          textInputAction: TextInputAction.next,
          onEditingComplete: () => node.nextFocus(), // Move focus to next
        ),
        TextField(
          decoration: InputDecoration(hintText: 'TextField B'),
          textInputAction: TextInputAction.next,
          onEditingComplete: () => node.nextFocus(), // Move focus to next
        ),
        TextField(
          decoration: InputDecoration(hintText: 'TextField C'),
          textInputAction: TextInputAction.done,
          onSubmitted: (_) => node.unfocus(), // Submit and hide keyboard
        ),
      ],
    ),
  );
}

11
感谢这一点,它并不复杂且易于应用。
艾伦·安德烈·英德菲佐

这仍然需要您单击“完成”按钮以集中到下一个输入。自动对焦怎么样。自动移至下一个字段?
Yuhao

2
@Yuhao您也可以使用onChangedproperty来实现。
CopsOnRoad

2
@CopsOnRoad很棒的答案。超级简单。这应该是公认的答案
Ty Irvine,

1
InputDatePickerFormField没有实现textInputAction:/
OOM

86

找到了一种方法来实现它。

  1. 显示下一个图标而不是完成-将textInputAction参数设置为TextInputAction.next

  2. 使用onFieldSubmitted回调请求下一个字段的焦点节点。

    class FormWidget extends StatelessWidget{    
       final focus = FocusNode();
       @override
       Widget build(BuildContext context) {
        return Form(
          child: SingleChildScrollView(
            padding: EdgeInsets.symmetric(horizontal: 16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                TextFormField(
                  textInputAction: TextInputAction.next,
                  autofocus: true,
                  decoration: InputDecoration(labelText: "Input 1"),
                  onFieldSubmitted: (v){
                    FocusScope.of(context).requestFocus(focus);
                  },
                ),
                TextFormField(
                  focusNode: focus,
                  decoration: InputDecoration(labelText: "Input 2"),
                ),
              ],
            ),
          ),
        );
      }
    }
    

编辑:如文档所述(flutter.io/docs/cookbook/forms/focus),-我们还需要管理FocusNode生命周期。因此,请使用init()方法中的init FocusNode并将其放置在父Widget的dispose()中。-@AntonDerevyanko

更新:如果没有FocusNodeFocusScopeNode,只需调用FocusScope.of(context).nextFocus(),看看CopsOnRoad解决方案的实现方法,就可以实现相同的目的。有关更多信息,请检查doc


10
如文档(flutter.io/docs/cookbook/forms/focus)中所述,-我们还需要管理FocusNode生命周期。因此,请使用init()方法中的init FocusNode并将其放置在父Widget的dispose()中。
安东·德雷夫扬科

@Harsh如果有两个以上的TextFormFields怎么办?6
fajar ainul

@fajarainul逻辑保持不变。onFieldSubmitted的第二场比赛requestFocus的第三场
比赛的对手

此解决方案有一个错误。如果按Tab键,则Tab键不仅会更改焦点,而且还会以文本形式添加到表单字段中-这不是表单的正常行为。制表符应更改焦点或输入文本,而不能两者都更改。
user48956 '19

3
而不是FocusScope.of(context).requestFocus(focus);您可以简单地致电focus.requestFocus()
安东尼奥,

9

这是CopsOnRoad答案的其他步骤,因为当文本字段之间存在可聚焦的小部件时,它在更复杂的UI中不起作用,例如:

  • 当密码字段具有可点击的切换图标时
  • 当字段之间有一个按钮(或其他可聚焦的小部件)时...

解决方案是继续调用“ nextFocus()”直到找到“ EditableText”

   @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: Column(
          children: <Widget>[
            TextField(
              decoration: InputDecoration(hintText: "TextField A"),
              textInputAction: textInputAction1,
              onSubmitted: (_) => context.nextEditableTextFocus(), // move focus to next
            ),
            TextField(
              decoration: InputDecoration(hintText: "TextField B"),
              textInputAction: textInputAction2,
              onSubmitted: (_) => context.nextEditableTextFocus(), // move focus to next
            ),
            MaterialButton(
             onPressed: () {},
             color: Colors.amber,
            ),
            TextField(
              decoration: InputDecoration(hintText: "TextField C"),
              textInputAction: textInputAction3,
              onSubmitted: (_) => FocusScope.of(context).unfocus(), // submit and hide keyboard
            ),
          ],
        ),
      );
    }

扩展方法是:

extension Utility on BuildContext {
  void nextEditableTextFocus() {
    do {
      FocusScope.of(this).nextFocus();
    } while (FocusScope.of(this).focusedChild.context.widget is! EditableText);
  }
}

5

对于TextFormFeild使用,可以使用onFieldSubmitted

TextFormField(
          decoration: InputDecoration(hintText: "Username"),
          textInputAction: TextInputAction.next,
          onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(), // focus to next
        ),
TextFormField(
          decoration: InputDecoration(hintText: "Password"),
          textInputAction: TextInputAction.done,
          onFieldSubmitted: (_) => FocusScope.of(context).unfocus(), // Unfocus and hide keyboard
        ),

1
@rexxar对不起,这是我现在已对其进行编辑的输入错误。
Maddu Swaroop '20年

4

对我而言,此方法有效,在输入第一个数字时移至下一个输入

Row(
                  children: <Widget>[
                    Expanded(
                      child: TextFormField(
                        textInputAction: TextInputAction.next,
                        onChanged: (_) => FocusScope.of(context).nextFocus(),
                          controller:c1 ,)
                    ),
                    SizedBox(
                      width: 20.0,
                    ),
                    Expanded(
                      child: TextFormField(
                        textInputAction: TextInputAction.next,
                        onChanged: (_) => FocusScope.of(context).nextFocus(),
                          controller:c2 ,),
                    ),
                    SizedBox(
                      width: 20.0,
                    ),
                    Expanded(
                      child: TextFormField(
                          controller:c3 ,
                        textInputAction: TextInputAction.next,
                        onChanged: (_) => FocusScope.of(context).nextFocus(),),
                    ),
                    SizedBox(
                      width: 20.0,
                    ),
                    Expanded(
                      child: TextFormField(
                          controller:c4 ,
                        textInputAction: TextInputAction.next,
                        onChanged: (_) => FocusScope.of(context).nextFocus(),),
                    ),
                    SizedBox(
                      width: 20.0,
                    ),
                    Expanded(
                      child: TextFormField(

                          controller:c5 ,
                        textInputAction: TextInputAction.next,
                        onChanged: (_) => FocusScope.of(context).nextFocus(),),
                    ),
                    SizedBox(
                      width: 20.0,
                    ),
                    Expanded(
                      child: TextFormField(
                          controller:c6 ,
                        textInputAction: TextInputAction.next,
                        onChanged: (_) => FocusScope.of(context).unfocus(),
                          ),
                    )
                  ],
                )

我使用您的代码将文本字段彼此相邻设置,我是扑扑的新手。谢谢!
尼拉吉

1

我用 onSubmitted代替onFieldSubmitted

范例程式码

      TextField(
                textInputAction: TextInputAction.next,
                onSubmitted: (_) => FocusScope.of(context).nextFocus(),
                controller: _phoneController,
                decoration: const InputDecoration(
                  labelText: 'Phone number',
                ),
                style: TextStyle(fontSize: 16.0, color: Colors.white),
              ),

0

您可以使用此帮助器功能来聚焦下一个文本字段:

void focusNextTextField(BuildContext context) {
  do {
    var foundFocusNode = FocusScope.of(context).nextFocus();
    if (!foundFocusNode) return;
  } while (FocusScope.of(context).focusedChild.context.widget is! EditableText);
}
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.