在某些情境中,我们可能需要在每次文本框的文本内容变化时都调用回调函数。例如,当构建一个有自动填充功能的搜索页面时,我们希望根据用户输入的内容来更新返回的结果。
那么如何每次在文本内容改变时调用回调函数呢?在Flutter中,我们提供了两种选择:
给
TextField
绑定onChanged
回调使用
TextEditingController
1. 给 TextField 绑定 onChanged 回调
最简单的方法是给 TextField
绑定 onChanged
回调。每当文本内容改变时,回调函数会被触发。但这种方法有一个缺点,它不适用于 TextFormField
组件。
在下面的示例中,每次 text 的值改变,会在控制台中打印出当前文本框的值。
TextField(
onChanged: (text) {
print("First text field: $text");
},
);
2. 使用 TextEditingController
另外一种更强大但是更复杂的方法是绑定 TextEditingController
作为 TextField
和 TextFormField
的 controller
属性
想要在文本更改时收到通知,我们可以使用 addListener
方法来监听控制器。
步骤
创建一个
TextEditingController
将
TextEditingController
绑定到TextField
创建一个函数来打印最新值
监听控制器的变化
创建一个 TextEditingController
首先,我们需要创建一个 TextEditingController
,然后将 TextField
绑定 TextEditingController
。一旦将这两个类绑定在一起,我们就可以监听文本框的改变了!
// Define a Custom Form Widget
class MyCustomForm extends StatefulWidget {
@override
_MyCustomFormState createState() => _MyCustomFormState();
}
// Define a corresponding State class. This class will hold the data related to
// our Form.
class _MyCustomFormState extends State<MyCustomForm> {
// Create a text controller. We will use it to retrieve the current value
// of the TextField!
final myController = TextEditingController();
@override
void dispose() {
// Clean up the controller when the Widget is removed from the Widget tree
myController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// We will fill this out in the next step!
}
}
注意:请在 TextEditingController
使用完毕时将其 dispose
,从而确保所有被这个对象所使用的资源被释放。
给 TextField 绑定 TextEditingController
TextEditingController
必须绑定到 TextField
或者是 TextFormField
才能被正常的使用。一旦绑定,就能够开始监听文本框的变化。
TextField(
controller: myController,
);
创建一个打印当前值的方法
现在,我们需要一个每当表单项变化都会运行的函数!在下面的示例中,我们会创建一个打印文本框当前值的方法。
这个方法将存在于 _MyCustomFormState
类中。
_printLatestValue() {
print("Second text field: ${myController.text}");
}
监听控制器的变化
最后,需要监听 TextEditingController
并且在 text 值变化时运行 _printLatestValue
方法。我们需要使用addListener
方法来实现这个功能。
下面的示例会在类 _MyCustomFormState
初始化的时候开始监听变化,dispose 时停止监听。
class _MyCustomFormState extends State<MyCustomForm> {
@override
void initState() {
super.initState();
// Start listening to changes
myController.addListener(_printLatestValue);
}
}
完整样例
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Retrieve Text Input',
home: MyCustomForm(),
);
}
}
// Define a Custom Form Widget
class MyCustomForm extends StatefulWidget {
@override
_MyCustomFormState createState() => _MyCustomFormState();
}
// Define a corresponding State class. This class will hold the data related to
// our Form.
class _MyCustomFormState extends State<MyCustomForm> {
// Create a text controller. We will use it to retrieve the current value
// of the TextField!
final myController = TextEditingController();
@override
void initState() {
super.initState();
myController.addListener(_printLatestValue);
}
@override
void dispose() {
// Clean up the controller when the Widget is removed from the Widget tree
// This also removes the _printLatestValue listener
myController.dispose();
super.dispose();
}
_printLatestValue() {
print("Second text field: ${myController.text}");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Retrieve Text Input'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
TextField(
onChanged: (text) {
print("First text field: $text");
},
),
TextField(
controller: myController,
),
],
),
),
);
}
}