在某些情況下,每當文字欄位中的文字發生變化時,執行一個回撥函式會很有用。例如,你可能想構建一個帶有自動補全功能的搜尋螢幕,你希望在使用者輸入時更新結果。

你如何做到每次文字更改時都執行一個回撥函式?在 Flutter 中,你有兩個選項

  1. TextFieldTextFormField 提供一個 onChanged() 回撥。
  2. 使用 TextEditingController

1. 為 TextFieldTextFormField 提供一個 onChanged() 回撥

#

最簡單的方法是為 TextFieldTextFormField 提供一個 onChanged() 回撥。每當文字發生變化時,就會呼叫此回撥。

在此示例中,每次文字更改時,都會將文字欄位的當前值和長度列印到控制檯。

處理使用者輸入時使用 characters 包很重要,因為文字可能包含複雜字元。這可以確保每個字元都像使用者看到的那樣被正確計數。

dart
TextField(
  onChanged: (text) {
    print('First text field: $text (${text.characters.length})');
  },
),

2. 使用 TextEditingController

#

一個更強大但更復雜的方法是,將一個 TextEditingController 作為 TextFieldTextFormFieldcontroller 屬性提供。

要在文字更改時得到通知,請按照以下步驟使用 addListener() 方法監聽控制器

  1. 建立 TextEditingController
  2. TextEditingController 連線到文字欄位。
  3. 建立列印最新值的函式。
  4. 監聽控制器以獲取更改。

建立 TextEditingController

#

建立 TextEditingController

dart
// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
  const MyCustomForm({super.key});

  @override
  State<MyCustomForm> 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.
  }
}

TextEditingController 連線到文字欄位

#

TextEditingController 提供給 TextFieldTextFormField。一旦將這兩個類連線起來,你就可以開始監聽文字欄位的更改了。

dart
TextField(controller: myController),

建立列印最新值的函式

#

你需要一個函式,在每次文字更改時執行。在 _MyCustomFormState 類中建立一個方法,打印出文字欄位的當前值。

dart
void _printLatestValue() {
  final text = myController.text;
  print('Second text field: $text (${text.characters.length})');
}

監聽控制器以獲取更改

#

最後,監聽 TextEditingController 並在文字更改時呼叫 _printLatestValue() 方法。為此,請使用 addListener() 方法。

_MyCustomFormState 類初始化時開始監聽更改,並在 _MyCustomFormState 銷燬時停止監聽。

dart
@override
void initState() {
  super.initState();

  // Start listening to changes.
  myController.addListener(_printLatestValue);
}
dart
@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();
}

互動示例

#
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Retrieve Text Input',
      home: MyCustomForm(),
    );
  }
}

// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
  const MyCustomForm({super.key});

  @override
  State<MyCustomForm> 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();

    // Start listening to changes.
    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();
  }

  void _printLatestValue() {
    final text = myController.text;
    print('Second text field: $text (${text.characters.length})');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Retrieve Text Input')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            TextField(
              onChanged: (text) {
                print('First text field: $text (${text.characters.length})');
              },
            ),
            TextField(controller: myController),
          ],
        ),
      ),
    );
  }
}