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

Har*_*dia 10 dart flutter flutter-layout

我是Flutter的新手.

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

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

Cop*_*oad 177

截屏:

在此处输入图片说明


只需使用:

textInputAction: TextInputAction.next:将光标移动到下一个字段。

textInputAction: TextInputAction.done: 关闭键盘。

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Column(
      children: <Widget>[
        TextField(
          decoration: InputDecoration(hintText: 'TextField A'),
          textInputAction: TextInputAction.next, // Moves focus to next.
        ),
        TextField(
          decoration: InputDecoration(hintText: 'TextField B'),
          textInputAction: TextInputAction.next, // Moves focus to next.
        ),
        TextField(
          decoration: InputDecoration(hintText: 'TextField C'),
          textInputAction: TextInputAction.done, // Hides the keyboard.
        ),
      ],
    ),
  );
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢这个,并不复杂且易于应用。 (19认同)
  • 如果您在文本字段旁边使用“密码隐藏/显示按钮”,则“nextFocus()”将不起作用。 (4认同)
  • @Yuhao你也可以使用`onChanged`属性来做到这一点。 (2认同)
  • @CopsOnRoad 很棒的答案。超级简单。这应该是公认的答案 (2认同)

Har*_*dia 27

找到了实现它的方法.

  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"),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 如文档(https://flutter.io/docs/cookbook/forms/focus)中所述,-我们还需要管理FocusNode生命周期。因此,请使用init()方法中的init FocusNode并将其放置在父Widget的dispose()中。 (6认同)
  • 您可以简单地调用“focus.requestFocus()”,而不是“FocusScope.of(context).requestFocus(focus);” (5认同)

Hay*_*mar 21

这是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
            ),
          ],
        ),
      );
    }
Run Code Online (Sandbox Code Playgroud)

其中扩展方法是:

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

  • 这几乎成功了,我不得不用“onEditingComplete: ()”替换“onSubscribed: (_)”以使其适用于更困难的布局 (2认同)
  • 花了近3个小时研究这个问题。这次真是万分感谢。登录表单从来没有出现过问题,因为电子邮件字段没有图标,密码按钮设置为不聚焦,但是当使用旧密码字段和 2 个新密码字段重置密码时,标准 focusNext 每次都会关闭键盘,直到我发现这一点。 (2认同)

Mad*_*oop 9

对于 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
        ),
Run Code Online (Sandbox Code Playgroud)

不知道确切原因,但 onFieldSubmitted 有时会跳过一个或多个字段,在这种情况下 onEditingComplete 按预期工作

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


Zee*_*hdi 9

对我来说,这行得通,它在输入第一个数字时移动到下一个输入

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(),
                          ),
                    )
                  ],
                )
Run Code Online (Sandbox Code Playgroud)


小智 9

感谢 @haytham-anmar 分享的扩展和 @natesh-bhat 的扩展!

但由于树上的重大更改,这对于 Flutter 的未来版本将不再起作用EditableText(参考:将文本编辑操作移至 EditableTextState #90684)。

请考虑以下迁移代码:

迁移前:

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

迁移后:

extension Utility on BuildContext {
  void nextEditableTextFocus() {
    do {
      FocusScope.of(this).nextFocus();
    } while (FocusScope.of(this).focusedChild!.context == null);
  }
}
Run Code Online (Sandbox Code Playgroud)


Fun*_*der 5

我尝试只添加textInputAction属性,它没有其他任何东西。

也许新版本的 Flutter 改进了这个功能?或者需要 StatefulWidget 和 FormKey 才能正常工作?

我在 Flutter 上(通道稳定,1.22.5)

试一试:

class MyForm extends StatefulWidget {
  @override
  State createState() => _myFormState();
}

class _myFormState extends State<MyForm> {
  //
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            // *** Just added this
            textInputAction: TextInputAction.next,
            decoration: const InputDecoration(
              labelText: 'Input 1',
            ),
          ),
          TextFormField(
            textInputAction: TextInputAction.done,
            decoration: const InputDecoration(
              labelText: 'Input 2',
            ),
          )
        ],
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)