flutter架 构项目基础
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# 【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` 让回车键变成"下一项",最后一项变"完成"。
|
||||
Reference in New Issue
Block a user