用户在颤动中输入1个字符后如何自动聚焦下一个文本字段

Posted

技术标签:

【中文标题】用户在颤动中输入1个字符后如何自动聚焦下一个文本字段【英文标题】:how to focus the next text field automatically after user input 1 character in flutter 【发布时间】:2021-09-08 21:31:40 【问题描述】:

我有 4 个textFormField 小部件。一旦用户完成了第一个文本字段,我想自动关注下一个textField。有没有办法在 Flutter 中做到这一点?任何人请分享,在此先感谢:)

【问题讨论】:

【参考方案1】:

这可以在 Flutter 中以不同的方式完成,我将尝试分享其中最简单的一种。在进入答案之前,值得一提的是以下问题:

Detect when delete is typed into a TextField #14809

在 Flutter 中,当 TextField 为空时,退格不会发送任何事件(即不会调用 TextField.onChanged)。在您的情况下,如果用户在第三个字段并且他们按退格键返回到第二个字段,那么如果没有链接问题中讨论的一些解决方法,就无法捕获该按键。简而言之,您需要添加一个零宽度空格字符(它不会被渲染但存在于字符串中)来检测退格事件。

我之所以提到这个问题,是因为我分享了一个利用零宽度空格字符(简称 zwsp)的示例。

在以下示例中,我只是创建了两个列表,其中包含:

FocusNode 每个字段 TextEditingController 对应每个字段。

基于索引,您可以通过调用将焦点带到特定字段: FocusNode.requestFocus().

同样,您可以通过调用FocusNode.unfocus 来移除焦点,或者您可以通过调用FocusScope.of(context).unfocus(); 从任何位置移除任何焦点(在下面的示例中,它用于在插入最后一个字符后隐藏键盘)。

话虽如此,这是一个完整的示例,您可以复制并粘贴来试用:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  


class MyHomePage extends StatelessWidget 
  final String title;
  MyHomePage(Key key, this.title) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(child: CodeField()),
    );
  


/// zero-width space character
///
/// this character can be added to a string to detect backspace.
/// The value, from its name, has a zero-width so it's not rendered
/// in the screen but it'll be present in the String.
///
/// The main reason this value is used because in Flutter mobile,
/// backspace is not detected when there's nothing to delete.
const zwsp = '\u200b';

// the selection is at offset 1 so any character is inserted after it.
const zwspEditingValue = TextEditingValue(text: zwsp, selection: TextSelection(baseOffset: 1, extentOffset: 1));

class CodeField extends StatefulWidget 
  const CodeField(Key key) : super(key: key);

  @override
  _CodeFieldState createState() => _CodeFieldState();


class _CodeFieldState extends State<CodeField> 
  List<String> code = ['', '', '', ''];

  List<TextEditingController> controllers;
  List<FocusNode> focusNodes;

  @override
  void initState() 
    // TODO: implement initState
    super.initState();
    focusNodes = List.generate(4, (index) => FocusNode());
    controllers = List.generate(4, (index) 
      final ctrl = TextEditingController();
      ctrl.value = zwspEditingValue;
      return ctrl;
    );

    WidgetsBinding.instance.addPostFrameCallback((timeStamp) 
      // give the focus to the first node.
      focusNodes[0].requestFocus();
    );
  

  @override
  void dispose() 
    // TODO: implement dispose
    super.dispose();
    focusNodes.forEach((focusNode) 
      focusNode.dispose();
    );
    controllers.forEach((controller) 
      controller.dispose();
    );
  

  @override
  Widget build(BuildContext context) 
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: List.generate(
        4,
        (index) 
          return Container(
            width: 20,
            height: 20,
            margin: const EdgeInsets.all(10),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(10),
            ),
            child: TextField(
              controller: controllers[index],
              focusNode: focusNodes[index],
              maxLength: 2,
              keyboardType: TextInputType.number,
              decoration: InputDecoration(
                counterText: "",
              ),
              onChanged: (value) 
                if (value.length > 1) 
                  // this is a new character event
                  if (index + 1 == focusNodes.length) 
                    // do something after the last character was inserted
                    FocusScope.of(context).unfocus();
                   else 
                    // move to the next field
                    focusNodes[index + 1].requestFocus();
                  
                 else 
                  // this is backspace event

                  // reset the controller
                  controllers[index].value = zwspEditingValue;
                  if (index == 0) 
                    // do something if backspace was pressed at the first field

                   else 
                    // go back to previous field
                    controllers[index - 1].value = zwspEditingValue;
                    focusNodes[index - 1].requestFocus();
                  
                
                // make sure to remove the zwsp character
                code[index] = value.replaceAll(zwsp, '');
                print('current code = $code');
              ,
            ),
          );
        ,
      ),
    );
  



【讨论】:

不幸的是,这打破了 ios 上的大写【参考方案2】:

您可能希望在每个TextFormField 上使用FocusNode,这样,一旦您的用户在TextFormField 中输入文本,您就可以在TextFormField 调用的回调onChanged 中使用myNextTextFieldFocusNode.requestFocus()


  FocusNode textFieldOne = FocusNode();
  FocusNode textFieldTwo = FocusNode();

  // ...

  TextFormField(
        onChanged: (_) 
           textFieldTwo.requestFocus();
        ,
        focusNode: textFieldOne,
        controller: textController,
  )

【讨论】:

【参考方案3】:

您可以使用 onChanged 和 nodefocus 属性。当 onchanged 被调用时,请参考下一个文本字段。

初始化一个焦点节点;

  late FocusNode myFocusNode;

  @override
  void initState() 
    super.initState();

    myFocusNode = FocusNode();
  

  @override
  void dispose() 
    // Clean up the focus node when the Form is disposed.
    myFocusNode.dispose();

    super.dispose();
  

onChanged 属性;

TextField(
  focusNode: myFocusNode1,
  onChanged: (text) 

   myFocusNode2.requestFocus();// I could not remember the correct usage please check
  ,
),

【讨论】:

以上是关于用户在颤动中输入1个字符后如何自动聚焦下一个文本字段的主要内容,如果未能解决你的问题,请参考以下文章

iPhone-在 UITextField 上辞职第一响应者后,无法重新聚焦

java 如何 按回车 光标换到下个输入框

如何在颤动中自动注销firebase用户?

Flutter 完美的验证码输入框(2 种方法)

Flutter 完美的验证码输入框(2 种方法)

如何在颤动中自动登录现有用户