在某些情境中,我们可能需要在每次文本框的文本内容变化时都调用回调函数。例如,当构建一个有自动填充功能的搜索页面时,我们希望根据用户输入的内容来更新返回的结果。

那么如何每次在文本内容改变时调用回调函数呢?在Flutter中,我们提供了两种选择:

  • TextField 绑定 onChanged 回调

  • 使用 TextEditingController

1. 给 TextField 绑定 onChanged 回调

最简单的方法是给 TextField 绑定 onChanged 回调。每当文本内容改变时,回调函数会被触发。但这种方法有一个缺点,它不适用于 TextFormField 组件。

在下面的示例中,每次 text 的值改变,会在控制台中打印出当前文本框的值。

  1. TextField(
  2. onChanged: (text) {
  3. print("First text field: $text");
  4. },
  5. );

2. 使用 TextEditingController

另外一种更强大但是更复杂的方法是绑定 TextEditingController 作为 TextFieldTextFormFieldcontroller 属性

想要在文本更改时收到通知,我们可以使用 addListener 方法来监听控制器。

步骤

  • 创建一个 TextEditingController

  • TextEditingController 绑定到 TextField

    • 创建一个函数来打印最新值

    • 监听控制器的变化​

创建一个 TextEditingController

首先,我们需要创建一个 TextEditingController ,然后将 TextField 绑定 TextEditingController 。一旦将这两个类绑定在一起,我们就可以监听文本框的改变了!

  1. // Define a Custom Form Widget
  2. class MyCustomForm extends StatefulWidget {
  3. @override
  4. _MyCustomFormState createState() => _MyCustomFormState();
  5. }
  6. // Define a corresponding State class. This class will hold the data related to
  7. // our Form.
  8. class _MyCustomFormState extends State<MyCustomForm> {
  9. // Create a text controller. We will use it to retrieve the current value
  10. // of the TextField!
  11. final myController = TextEditingController();
  12. @override
  13. void dispose() {
  14. // Clean up the controller when the Widget is removed from the Widget tree
  15. myController.dispose();
  16. super.dispose();
  17. }
  18. @override
  19. Widget build(BuildContext context) {
  20. // We will fill this out in the next step!
  21. }
  22. }

注意:请在 TextEditingController 使用完毕时将其 dispose ,从而确保所有被这个对象所使用的资源被释放。

给 TextField 绑定 TextEditingController

TextEditingController 必须绑定到 TextField 或者是 TextFormField 才能被正常的使用。一旦绑定,就能够开始监听文本框的变化。

  1. TextField(
  2. controller: myController,
  3. );

创建一个打印当前值的方法

现在,我们需要一个每当表单项变化都会运行的函数!在下面的示例中,我们会创建一个打印文本框当前值的方法。

这个方法将存在于 _MyCustomFormState 类中。

  1. _printLatestValue() {
  2. print("Second text field: ${myController.text}");
  3. }

监听控制器的变化

最后,需要监听 TextEditingController 并且在 text 值变化时运行 _printLatestValue 方法。我们需要使用addListener方法来实现这个功能。

下面的示例会在类 _MyCustomFormState 初始化的时候开始监听变化,dispose 时停止监听。

  1. class _MyCustomFormState extends State<MyCustomForm> {
  2. @override
  3. void initState() {
  4. super.initState();
  5. // Start listening to changes
  6. myController.addListener(_printLatestValue);
  7. }
  8. }

完整样例

  1. import 'package:flutter/material.dart';
  2. void main() => runApp(MyApp());
  3. class MyApp extends StatelessWidget {
  4. @override
  5. Widget build(BuildContext context) {
  6. return MaterialApp(
  7. title: 'Retrieve Text Input',
  8. home: MyCustomForm(),
  9. );
  10. }
  11. }
  12. // Define a Custom Form Widget
  13. class MyCustomForm extends StatefulWidget {
  14. @override
  15. _MyCustomFormState createState() => _MyCustomFormState();
  16. }
  17. // Define a corresponding State class. This class will hold the data related to
  18. // our Form.
  19. class _MyCustomFormState extends State<MyCustomForm> {
  20. // Create a text controller. We will use it to retrieve the current value
  21. // of the TextField!
  22. final myController = TextEditingController();
  23. @override
  24. void initState() {
  25. super.initState();
  26. myController.addListener(_printLatestValue);
  27. }
  28. @override
  29. void dispose() {
  30. // Clean up the controller when the Widget is removed from the Widget tree
  31. // This also removes the _printLatestValue listener
  32. myController.dispose();
  33. super.dispose();
  34. }
  35. _printLatestValue() {
  36. print("Second text field: ${myController.text}");
  37. }
  38. @override
  39. Widget build(BuildContext context) {
  40. return Scaffold(
  41. appBar: AppBar(
  42. title: Text('Retrieve Text Input'),
  43. ),
  44. body: Padding(
  45. padding: const EdgeInsets.all(16.0),
  46. child: Column(
  47. children: <Widget>[
  48. TextField(
  49. onChanged: (text) {
  50. print("First text field: $text");
  51. },
  52. ),
  53. TextField(
  54. controller: myController,
  55. ),
  56. ],
  57. ),
  58. ),
  59. );
  60. }
  61. }