簡體   English   中英

如何將焦點轉移到Flutter中的下一個TextField?

[英]How to shift focus to the next TextField in Flutter?

我是 Flutter 的新用戶。

我正在使用以下小部件構建具有多個文本輸入的表單:Form、TextFormField。 出現的鍵盤不顯示“下一步”(應將焦點轉移到下一個字段)字段操作,而是“完成”操作(隱藏鍵盤)。

我在官方文檔中尋找任何提示,沒有發現任何可以直接完成的事情。 我雖然登陸了 FocusNode( cookbookapi doc )。 它提供了通過某個按鈕或應用程序上的任何其他操作來轉移焦點的機制,但我希望它位於keyboard中。

截屏:

在此處輸入圖片說明


只需使用:

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

找到了實現它的方法。

  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() 方法中初始化 FocusNode 並在父 Widget 的 dispose() 中進行處置。 - @AntonDerevyanko

更新:在沒有FocusNodeFocusScopeNode情況下也可以實現相同的效果,只需調用FocusScope.of(context).nextFocus() ,看看如何做到這一點的CopsOnRoad 解決方案 有關更多信息,請查看文檔

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

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

不知道確切原因,但 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
        ),

對我來說,這行得通,它在輸入第一個數字時移動到下一個輸入

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

我嘗試只添加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',
            ),
          )
        ],
      ),
    );
  }
}

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

感謝@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);
  }
}

遷移后:

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

您可以使用此輔助函數聚焦下一個文本字段:

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

我希望它有用

textInputAction: TextInputAction.next,
        onEditingComplete: () {
             FocusScope.of(context).nextFocus();
        },
        onSubmitted: (value) {
            if (value.isNotEmpty) {
                  FocusScope.of(context).nextFocus();
            }
        },

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM