跳至主要內容

處理文字欄位的變更

在某些情況下,每次文字欄位中的文字變更時都執行回呼函式會很有用。例如,您可能想要建立具有自動完成功能的搜尋畫面,以便在使用者輸入時更新結果。

如何讓每次文字變更時都執行回呼函式?使用 Flutter,您有兩種選擇

  1. 提供 onChanged() 回呼函式給 TextFieldTextFormField
  2. 使用 TextEditingController

1. 提供 onChanged() 回呼函式給 TextFieldTextFormField

#

最簡單的方法是提供 onChanged() 回呼函式給 TextFieldTextFormField。每當文字變更時,就會呼叫回呼函式。

在此範例中,每次文字變更時,都會將文字欄位的目前值和長度列印到主控台。

處理使用者輸入時,務必使用 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,
            ),
          ],
        ),
      ),
    );
  }
}