# 【Demo】TextField 输入框(登录表单) > 源文件:`lib/pages/demo/input_demo.dart` | 分类:基础布局 > 一句话:输入框 + 密码"小眼睛"切换 —— 表单最基础的零件。 --- ## 一、这个 Demo 解决什么问题 做一个最简单的登录表单:手机号输入框 + 密码输入框(可切换明文/密文)。 核心是搞懂 **TextEditingController** 的用法——Flutter 里输入框不叫"双向绑定", 而是"控制器持有值,代码里随时读写"。 --- ## 二、怎么运行 / 演示内容 ```dart runApp(const MaterialApp(home: InputDemoPage())); ``` - 手机号框:弹数字键盘(`keyboardType: TextInputType.phone`); - 密码框:右侧眼睛图标切换密文/明文; - 点"登录":控制台打印两个输入框的内容。 --- ## 三、核心知识点(新手向) ### 1. 对照 Vue 的 v-model | Vue | Flutter | |---|---| | `v-model="phone"` | `TextEditingController` + `controller.text` | | 框架自动同步 | 手动 `controller.text` 读写 | Flutter 没有隐式的双向绑定:`controller.text` 改了就同步到输入框, 输入框内容变了 `controller.text` 也会读到 —— 但**没有"响应式"**: 想根据输入内容实时刷新 UI(如"输入满 11 位才能点登录"),要自己 `addListener` 或 `setState`。 ### 2. TextEditingController 生命周期(红线) ```dart final TextEditingController _userCtrl = TextEditingController(); @override void dispose() { _userCtrl.dispose(); // 必须在 dispose 释放,防内存泄漏 super.dispose(); } ``` > 凡是用 `Controller` 命名的东西(Text/Scroll/Animation/Tab),基本都要 dispose。 ### 3. 密码眼睛切换 ```dart bool _showPwd = false; TextField( controller: _pwdCtrl, obscureText: !_showPwd, // 密文/明文由状态决定 decoration: InputDecoration( labelText: "密码", prefixIcon: const Icon(Icons.lock), border: const OutlineInputBorder(), suffixIcon: IconButton( icon: Icon(_showPwd ? Icons.visibility : Icons.visibility_off), onPressed: () => setState(() => _showPwd = !_showPwd), ), ), ) ``` ### 4. InputDecoration 常用参数 - `labelText`:浮动标签(聚焦时缩小浮到边框上); - `hintText`:灰色占位提示; - `prefixIcon`:左侧图标;`suffixIcon`:右侧(按钮/图标); - `border: OutlineInputBorder()`:带边框的圆角样式(默认是下划线)。 --- ## 四、关键代码剖析 ```dart // 读取输入内容(点登录时) String user = _userCtrl.text; String pwd = _pwdCtrl.text; if (kDebugMode) { print("账号:$user,密码:$pwd"); // kDebugMode:只在 debug 包打印 } ``` 要点: - `kDebugMode`(来自 `package:flutter/foundation.dart`)保证打印不会出现在 release 包; - 真实项目里读取后要走校验(见 [form_demo.md](form_demo.md))和登录接口(见 [dio_demo.md](dio_demo.md))。 --- ## 五、踩坑记录 1. **Scaffold 没有 `padding` 参数!** 外间距要写在 body 的 `Padding` 上(新手必踩)。 2. `controller` 忘了 dispose → 内存泄漏(Flutter 分析器会提示)。 3. `suffixIcon` 用 `IconButton` 而不要用普通 `Icon` 包 `GestureDetector` —— IconButton 自带点击区域和涟漪反馈。 4. 想"输入即校验"别自己写监听,直接上 Form(见 form_demo)。 --- ## 六、扩展思考 - 进阶校验:`TextFormField` + `validator`([form_demo.md](form_demo.md))—— 本项目表单校验全家桶; - 真实登录页还要:防重复提交、加载动画、错误提示、密码安全存储(本项目用 flutter_secure_storage,见架构文档存储层); - 输入法控制:`textInputAction: TextInputAction.next` 让回车键变成"下一项",最后一项变"完成"。