用 TextEditingController 驱动你的输入框,并借助 Form 和 TextFormField 一次性校验每一项输入。
在 Kodokon 中打开本课没有控制器的输入框就是一个黑盒。TextEditingController 让你掌握主动:随时读取 controller.text、预填输入框、在提交后清空它,或用 addListener 监听每一次按键。控制器要在 State 中创建,绝不能放在 build 里 - 否则它会在每次重建时被重新创建。
import 'package:flutter/material.dart';
class NicknameField extends StatefulWidget {
const NicknameField({super.key});
@override
State<NicknameField> createState() =>
_NicknameFieldState();
}
class _NicknameFieldState extends State<NicknameField> {
final _controller = TextEditingController();
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(
controller: _controller,
decoration: const InputDecoration(
labelText: 'Nickname',
border: OutlineInputBorder(),
),
onSubmitted: (value) => debugPrint(value),
);
}
}一旦某个界面有好几个字段需要校验,就采用 Form、GlobalKey<FormState> 和 TextFormField 这三件套。每个字段都在 validator 里描述自己的规则:这个函数返回一条错误消息,若一切正常则返回 null。对这个 key 调用一次 validate() 就会同时触发所有校验器。
import 'package:flutter/material.dart';
class SignUpForm extends StatefulWidget {
const SignUpForm({super.key});
@override
State<SignUpForm> createState() => _SignUpFormState();
}
class _SignUpFormState extends State<SignUpForm> {
final _formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
@override
void dispose() {
_emailController.dispose();
super.dispose();
}
void _submit() {
if (_formKey.currentState!.validate()) {
debugPrint('Email: ${_emailController.text}');
}
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
labelText: 'Email',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Required field';
}
if (!value.contains('@')) {
return 'Invalid address';
}
return null;
},
),
const SizedBox(height: 16),
FilledButton(
onPressed: _submit,
child: const Text('Create account'),
),
],
),
);
}
}当按钮被点击时,validate() 会运行每一个 validator:返回的消息会以红色显示在对应字段的下方,只要至少有一个字段不合法,该方法就返回 false。因此你的提交逻辑始终守在一个 if 后面 - 想提交非法数据根本不可能。