Bài 7. Nhập liệu và biểu mẫu (Form)

Hầu hết ứng dụng đều cần nhập liệu: đăng nhập, đăng ký, tìm kiếm. Bài này dạy TextField, TextEditingController, Form với kiểm tra hợp lệ và các điều khiển chọn.

50 phútCơ bản
Bạn sẽ học được
  • Dùng TextField và TextEditingController
  • Xây dựng Form với validator
  • Dùng Checkbox, Switch, Radio, Dropdown, DatePicker
  • Quản lý bàn phím và focus
Thuật ngữ cần biết
Controller
Đối tượng đọc/ghi giá trị ô nhập.
Validator
Hàm trả về chuỗi lỗi hoặc null nếu hợp lệ.
GlobalKey<FormState>
Khóa để truy cập và kiểm tra toàn bộ Form.
FocusNode
Quản lý ô đang được nhập.

Khái niệm và lý thuyết

Mỗi ô nhập giữ giá trị trong một TextEditingController. Controller là tài nguyên nên phải tạo trong initState (hoặc khai báo trường) và giải phóng trong dispose.

Form gom nhiều TextFormField; khi gọi formKey.currentState!.validate(), Flutter chạy validator của từng ô và hiện thông báo lỗi ngay dưới ô sai. Kiểm tra phía ứng dụng chỉ để trải nghiệm tốt hơn; máy chủ vẫn phải kiểm tra lại.

Form đăng nhập

class DangNhap extends StatefulWidget {
  const DangNhap({super.key});
  @override
  State<DangNhap> createState() => _DangNhapState();
}
class _DangNhapState extends State<DangNhap> {
  final _formKey = GlobalKey<FormState>();
  final _email = TextEditingController();
  final _matKhau = TextEditingController();
  bool _an = true;

  @override
  void dispose() { _email.dispose(); _matKhau.dispose(); super.dispose(); }

  @override
  Widget build(BuildContext context) => Form(
    key: _formKey,
    child: Column(children: [
      TextFormField(
        controller: _email,
        keyboardType: TextInputType.emailAddress,
        decoration: const InputDecoration(labelText: 'Email', prefixIcon: Icon(Icons.email)),
        validator: (v) => (v == null || !v.contains('@')) ? 'Email không hợp lệ' : null,
      ),
      TextFormField(
        controller: _matKhau,
        obscureText: _an,
        decoration: InputDecoration(labelText: 'Mật khẩu',
          suffixIcon: IconButton(icon: Icon(_an ? Icons.visibility : Icons.visibility_off),
                                 onPressed: () => setState(() => _an = !_an))),
        validator: (v) => (v ?? '').length < 8 ? 'Tối thiểu 8 ký tự' : null,
      ),
      const SizedBox(height: 16),
      FilledButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Xin chào ${_email.text}')));
          }
        },
        child: const Text('Đăng nhập')),
    ]),
  );
}

Các điều khiển chọn

WidgetDùng cho
Checkbox / CheckboxListTileĐồng ý điều khoản, chọn nhiều
Switch / SwitchListTileBật tắt
RadioGroup + RadioListTileChọn một trong nhiều
DropdownMenuDanh sách thả xuống
showDatePickerChọn ngày
SliderChọn giá trị trong khoảng
final ngay = await showDatePicker(
  context: context, firstDate: DateTime(1950), lastDate: DateTime.now());
Mẹo hay

Đặt textInputAction: TextInputAction.next để nút Enter trên bàn phím chuyển sang ô kế tiếp, và autofillHints để hệ điều hành gợi ý email, mật khẩu đã lưu.

Lưu ý

Bàn phím ảo che ô nhập khi màn hình dài: bọc nội dung trong SingleChildScrollView hoặc ListView.

Thực hành
  1. Hoàn thiện form đăng nhập ở trên, thêm ô “Ghi nhớ” bằng CheckboxListTile.
  2. Tạo form đăng ký: họ tên, email, ngày sinh (DatePicker), giới tính (Radio), ngành học (Dropdown).
  3. Kiểm tra mật khẩu nhập lại phải trùng.
  4. Hiển thị dữ liệu đã nhập trong AlertDialog khi bấm Gửi.
Tóm tắt bài học
  • TextEditingController đọc/ghi ô nhập và phải dispose.
  • Form + validator kiểm tra dữ liệu tập trung.
  • Flutter có sẵn đủ điều khiển chọn và hộp thoại ngày.
  • Chú ý bàn phím, focus và autofill để tăng trải nghiệm.