用户在颤动中输入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个字符后如何自动聚焦下一个文本字段的主要内容,如果未能解决你的问题,请参考以下文章