如何将焦点转移到扑动中的下一个文本字段?

我是新来的。

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

我在官方文件中寻找线索,没有发现任何直接可行的方法。 虽然我是在 FocusNode (食谱API 医生)上着陆的。它提供了一种机制,通过一些按钮或任何其他动作转移应用程序的焦点,但我希望它是在 键盘

95538 次浏览

找到了实现它的方法。

  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"),
    ),
    ],
    ),
    ),
    );
    }
    }
    

Edit: As stated in the documentation (flutter.io/docs/cookbook/forms/focus), - we also need to manage FocusNode lifecycle. So, init FocusNode in the init() method and dispose in dispose() of the parent Widget. - @AntonDerevyanko

Update: The same can be achieved without FocusNode and FocusScopeNode, by simply calling FocusScope.of(context).nextFocus(), take a look at CopsOnRoad solution on how to do that. For more info check doc.

截图:

enter image description here


使用:

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

关闭键盘。

@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.
),
],
),
);
}

对于 TextFormField,可以使用 onFieldSubmit

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
),

不知道确切的原因,但 onFieldSubmit 有时会跳过一个或多个字段,这种情况下 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
),

我用过 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),
),

这是 科普森路回答问题的附加步骤,因为当文本字段之间有可聚焦的小部件时,它不能在更复杂的 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);
}
}

对我来说,这个工作它移动到下一个输入输入第一个数字

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(),
),
)
],
)

您可以使用这个 helper 函数来关注下一个文本字段:

void focusNextTextField(BuildContext context) {
do {
var foundFocusNode = FocusScope.of(context).nextFocus();
if (!foundFocusNode) return;
} while (FocusScope.of(context).focusedChild.context.widget is! EditableText);
}

我尝试只添加 textInputAction属性,它不需要其他任何东西就可以工作。

也许新版本的 Flutter 已经改进了这个功能? 或者需要 StatefentWidget & FormKey 才能让它工作?

我在颤动(频道稳定,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',
),
)
],
),
);
}
}

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

但是由于 EditableText树(参考文献: 将文本编辑操作移至 EditableTextState # 90684)上的一个突破性变化,这将不再适用于 Flutter 未来的发行版。

请考虑以下迁移代码:

迁徙前:

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

迁徙后:

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