回應文字框內容的更改
在某些情境中,我們可能需要在每次文字框的文字內容變化時都呼叫回呼函式。例如,當建立一個有自動填充功能的搜尋頁面時,我們希望根據使用者輸入的內容來更新回傳的結果。
那麼如何每次在文字內容改變時調用回呼函式呢?在Flutter中,我們提供了兩種選擇:
-
給
TextField
或TextFormField
繫結onChanged()
回呼 -
使用
TextEditingController
TextField
或 TextFormField
繫結 onChanged()
回呼
1. 給 最簡單的方法是給 TextField
繫結 onChanged()
回呼。每當文字內容改變時,回呼函式會被觸發。
在下面的範例中,每次 text 的值改變,會在控制台中列印出當前文字框的值。
在處理使用者的輸入內容時,很重要的一點是要使用 characters,因為使用者的輸入內容可能會包含複雜的字元。 characters 會保證每一個顯示到使用者字元都被計數到。
TextField(
onChanged: (text) {
print('First text field: $text (${text.characters.length})');
},
),
TextEditingController
2. 使用 另外一種更強大但是更復雜的方法是繫結 TextEditingController
作為 TextField
和
TextFormField
的 controller
屬性。
你可以透過如下步驟,使用 addListener()
方法來監聽控制,實現在文字更改時收到通知:
-
建立一個
TextEditingController
-
將
TextEditingController
繫結到 text field -
建立一個函式來列印最新值
-
監聽控制器的變化
TextEditingController
建立一個 建立一個 TextEditingController
:
// 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
給 text field 繫結 TextEditingController
必須繫結到 TextField
或者是 TextFormField
才能被正常的使用。一旦繫結,就能夠開始監聽文字框的變化。
TextField(
controller: myController,
),
建立一個列印當前值的方法
現在,我們需要一個每當表單項變化都會執行的函式。在下面的範例中,我們會在 _MyCustomFormState
類別中建立一個方法,實現列印出文本框當前值。
void _printLatestValue() {
final text = myController.text;
print('Second text field: $text (${text.characters.length})');
}
監聽控制器的變化
最後,需要監聽 TextEditingController
並且在 text 值變化時運行
_printLatestValue()
方法。我們需要使用 addListener()
方法來實現這個功能。
下面的範例會在類 _MyCustomFormState
初始化的時候開始監聽變化,dispose 時停止監聽。
@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();
}
互動式範例
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,
),
],
),
),
);
}
}