响应文本框内容的更改

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

In some cases, it’s useful to run a callback function every time the text in a text field changes. For example, you might want to build a search screen with autocomplete functionality where you want to update the results as the user types.

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

How do you run a callback function every time the text changes? With Flutter, you have two options:

  1. TextFieldTextFormField 绑定 onChanged() 回调

    Supply an onChanged() callback to a TextField or a TextFormField.

  2. 使用 TextEditingController

    Use a TextEditingController.

1. 给 TextFieldTextFormField 绑定 onChanged() 回调

1. Supply an onChanged() callback to a TextField or a TextFormField

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

The simplest approach is to supply an onChanged() callback to a TextField or a TextFormField. Whenever the text changes, the callback is invoked.

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

In this example, print the current value of the text field to the console every time the text changes.

TextField(
  onChanged: (text) {
    print("First text field: $text");
  },
);

2. 使用 TextEditingController

2. Use a TextEditingController

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

A more powerful, but more elaborate approach, is to supply a TextEditingController as the controller property of the TextField or a TextFormField.

你可以通过如下步骤,使用 addListener() 方法来监听控制,实现在文本更改时收到通知:

To be notified when the text changes, listen to the controller using the addListener() method using the following steps:

  1. 创建一个 TextEditingController

    Create a TextEditingController.

  2. TextEditingController 绑定到 text field

    Connect the TextEditingController to a text field.

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

    Create a function to print the latest value.

  4. 监听控制器的变化

    Listen to the controller for changes.

创建一个 TextEditingController

Create a TextEditingController

创建一个 TextEditingController

Create a TextEditingController:

// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
  @override
  _MyCustomFormState createState() => _MyCustomFormState();
}

// Define a corresponding State class.
// This class holds data related to the Form.
class _MyCustomFormState extends State<MyCustomForm> {
  // Create a text controller. Later, 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) {
    // Fill this out in the next step.
  }
}

给 text field 绑定 TextEditingController

Connect the TextEditingController to a text field

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

Supply the TextEditingController to either a TextField or a TextFormField. Once you wire these two classes together, you can begin listening for changes to the text field.

TextField(
  controller: myController,
);

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

Create a function to print the latest value

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

You need a function to run every time the text changes. Create a method in the _MyCustomFormState class that prints out the current value of the text field.

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

监听控制器的变化

Listen to the controller for changes

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

Finally, listen to the TextEditingController and call the _printLatestValue() method when the text changes. Use the addListener() method for this purpose.

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

Begin listening for changes when the _MyCustomFormState class is initialized, and stop listening when the _MyCustomFormState is disposed.

class _MyCustomFormState extends State<MyCustomForm> {
  @override
  void initState() {
    super.initState();

    // Start listening to changes.
    myController.addListener(_printLatestValue);
  }
}

完整样例

Complete example

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 holds data related to the Form.
class _MyCustomFormState extends State<MyCustomForm> {
  // Create a text controller and 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,
            ),
          ],
        ),
      ),
    );
  }
}