(Flutter) 如何在不按“完成”的情况下自动监听 TextField 中的变化?
Posted
技术标签:
【中文标题】(Flutter) 如何在不按“完成”的情况下自动监听 TextField 中的变化?【英文标题】:(Flutter) How to listen changes in TextField automatically, without pressing "Done"? 【发布时间】:2019-03-18 15:38:21 【问题描述】:I 在对话框中从 TextField 打印输入(TextField 和输出都在 AlertDialog 中)。仅当我在键盘上按“完成”时才会更新输出。如果我不按 Done,它会一直显示旧的输出。
这是我的源代码:
Future<void> widePopUpCustom() async
return showDialog<void>(
context: context,
builder: (BuildContext context)
return AlertDialog(
title: Text('Enter Number'),
content: SingleChildScrollView(
child: ListBody(children: <Widget>[
TextField(
controller: customRun,
decoration: InputDecoration(
labelText: 'Number',
)),
Text('$customRun.text'),
])),
actions: <Widget>[
FlatButton(
child: Text('OK'), onPressed: () => Navigator.pop(context))
]);
);
我也声明了控制器:
final TextEditingController customRun = TextEditingController();
(进一步澄清)这是我的输出,我想在我的 TextField 中输入文本时实时更新,而不用在键盘上按完成
Text('$customRun.text'),
【问题讨论】:
【参考方案1】:对于演示,您可以看这里。 Example
1。识别需要重建的文本小部件
首先,我们希望这个小部件中的内容可以作为用户类型进行重建。
Text('$customRun.text'),
不幸的是,这个小部件位于 widePopUpCustom 方法中 警报对话框子项
void widePopUpCustom() async
await showDialog(
context: context,
builder: (BuildContext context)
return AlertDialog(
title: Text('Enter Number'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
TextField(
controller: customRun,
decoration: InputDecoration(
labelText: 'Number',
),
),
Text('$customRun.text'), // Needs to be re-rendered
],
),
),
);
,
);
在这种情况下,我们无法在 AlertDialog
小部件上触发重建,包括其所有子部件 ListBody
、TextField
和 Text
小部件。
2。拆分 AlertDialog
并将其转换为 Stateful Widget
我们考虑将AlertDialog
移动到AlertWrapper
,并将AlertWrapper
定义为Stateful Widget。所以稍后,我们可以使用以下代码触发AlertWrapper
的重建:
setState(())
我们可以结束这一步,将widePopUpCustom()
修改为这个:
Future<void> widePopUpCustom() async
return showDialog<void>(
context: context,
builder: (BuildContext context)
return AlertWrapper();
,
);
之前,AlertDialog 将被视为无状态,除非我们关闭对话框,否则不会重新渲染。
3。覆盖 Stateful Widget 以附加监听器
通过使用有状态小部件,我们可以探索 initState 的用法。在这种情况下,我们将addListener
附加到customRun
TextController。
请注意 changesOnField 方法。每次用户与键盘输入交互时都会触发此方法
class AlertWrapper extends StatefulWidget
const AlertWrapper(
Key key,
) : super(key: key);
@override
_AlertWrapperState createState() => _AlertWrapperState();
class _AlertWrapperState extends State<AlertWrapper>
final TextEditingController customRun = TextEditingController();
changesOnField()
print("Updated Text: $customRun.text");
setState(() ); // Will re-Trigger Build Method
@override
void initState()
super.initState();
customRun.addListener(changesOnField);
changesOnField 会触发 build 方法被重新调用,然后我们可以更新 Text 小部件中的值
@override
Widget build(BuildContext context)
return AlertDialog(
title: Text('Enter Number'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
TextField(
controller: customRun,
decoration: InputDecoration(
labelText: 'Number',
),
),
Text('$customRun.text'), // Finally re-rendered
],
),
),
完整的工作回购
你可以看看这个 repo。 Github
更多改进
正如official docs 所说,我们需要配置监听器来优化应用程序。
稍后我们可以添加此代码
@override
void dispose()
customRun.dispose();
super.dispose();
【讨论】:
【参考方案2】:您需要为文本字段添加onChanged(txt)
方法,并且它必须在其中包含setState()
以便在您每次键入字符时刷新文本
Future<void> widePopUpCustom() async
return showDialog<void>(
context: context,
builder: (BuildContext context)
return AlertDialog(
title: Text('Enter Number'),
content: SingleChildScrollView(
child: ListBody(children: <Widget>[
TextField(
controller: customRun,
decoration: InputDecoration(
labelText: 'Number',
)),
onChanged:(txt)
setState(()
customRun.text = txt;
),
,
Text('$customRun.text'),
])),
actions: <Widget>[
FlatButton(
child: Text('OK'), onPressed: () => Navigator.pop(context))
]);
);
【讨论】:
它仍然没有实时更新输出。只有当我在键盘上按“完成”时它才会更新。澄清一下:Text('$customRun.text'), is my output 我建议您添加一个新的字符串变量来存储输入并在文本视图中输出它,我经常使用它,它可以为我添加的每个字母工作和更新以上是关于(Flutter) 如何在不按“完成”的情况下自动监听 TextField 中的变化?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不按下按钮的情况下自动处理 <textarea> 的内容?