flutter架 构项目基础

This commit is contained in:
崔宝新
2026-09-04 15:22:20 +08:00
parent 70967229d0
commit 0c5aee59c0
265 changed files with 35484 additions and 0 deletions
+148
View File
@@ -0,0 +1,148 @@
# 【Demo】Text 文本组件全家桶
> 源文件:`lib/pages/demo/text_demo.dart` | 分类:基础布局
> 一句话:样式、对齐、截断、行高、富文本、可点击协议文本 —— 文本相关的细节一次看全。
---
## 一、这个 Demo 解决什么问题
Text 是 Flutter 里出现频率最高的组件,但细节坑不少:
- `textAlign` 为什么有时不生效?
- 超长文字怎么显示省略号?
- "已阅读并同意《用户协议》"这种**部分文字可点击**怎么做?
- 系统字体缩放怎么适配?
本页 7 个区块逐一演示。
---
## 二、怎么运行 / 演示内容
```dart
runApp(const MaterialApp(home: TextDemoPage()));
```
1. 基础样式(fontSize / color / fontWeight / fontStyle);
2. 对齐 textAlign(左/中/右);
3. 截断三件套(ellipsis / clip / softWrap:false);
4. 行高 height 对比(默认 / 1.2 / 2);
5. 字间距 letterSpacing / 词间距 wordSpacing;
6. 富文本 Text.rich + TextSpan + 可点击协议;
7. 字体缩放 textScaler。
---
## 三、核心知识点(新手向)
### 1. Text 全家桶速记
| 场景 | 组件 |
|---|---|
| 单样式文字 | `Text` |
| 富文本拼接(不同颜色/可点击段落) | `Text.rich` + `TextSpan` |
| 全局默认样式 | `DefaultTextStyle`(MaterialApp 自带,Text 会继承) |
### 2. textAlign 生效的前提
**Text 必须有宽度约束**,对齐才有空间生效:
```dart
Container(
width: 300.w,
child: Column(
// 关键:stretch 让每个子组件横向拉满,textAlign 才有空间生效
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('左对齐', textAlign: TextAlign.left),
Text('居中对齐', textAlign: TextAlign.center),
Text('右对齐', textAlign: TextAlign.right),
],
),
)
```
> 新手最常见的疑惑:在 Column 里写 `textAlign: center` 不居中 —— 因为 Text 宽度只包住文字。
> 要么 `crossAxisAlignment: center`(让 Text 居中),要么 `stretch` + `textAlign`(让文字在拉满的宽度里居中)。
### 3. 截断三件套(必须配齐)
```dart
Text(
'很长很长...',
maxLines: 1,
overflow: TextOverflow.ellipsis, // 末尾加省略号
)
```
- `ellipsis`:省略号;`clip`:直接裁掉;`softWrap: false` + `visible`:真·溢出画到盒子外;
- 前提同样是**有界宽度**(外面套固定宽 Container)。
### 4. 行高与间距
```dart
TextStyle(height: 1.2) // 行高倍数(1.0 = 紧凑,2.0 = 松散)
TextStyle(letterSpacing: 4) // 字间距(中文按字)
TextStyle(wordSpacing: 8) // 词间距(按空格分词,中文基本无效)
```
### 5. 富文本 + 可点击(协议文本的官方姿势)
```dart
Text.rich(
TextSpan(
children: [
TextSpan(text: '已阅读并同意', style: TextStyle(color: Color(0xFF888888))),
TextSpan(
text: '《用户协议》',
style: TextStyle(color: Color(0xFF3B82F6), fontWeight: FontWeight.bold),
recognizer: _agreementRecognizer, // 点击手势(必须 dispose!)
),
],
),
)
```
`TapGestureRecognizer` 必须放在 **StatefulWidget 里创建,并在 dispose() 里释放**(与 createState 一一对应,防内存泄漏)。
### 6. 字体缩放(Flutter 3.x)
```dart
Text('线性放大 1.5 倍', textScaler: TextScaler.linear(1.5));
// 读取系统缩放:MediaQuery.textScalerOf(context)
```
---
## 四、关键代码剖析
```dart
class _AgreementRichTextState extends State<_AgreementRichText> {
// late final:整个 State 生命周期只创建一次,复用同一个 recognizer
late final TapGestureRecognizer _agreementRecognizer = TapGestureRecognizer()
..onTap = _handleAgreementTap;
void _handleAgreementTap() {
// 点击回调可能晚于 dispose(点击瞬间页面被切走),用 mounted 兜底
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('点了《用户协议》')),
);
}
@override
void dispose() {
_agreementRecognizer.dispose(); // 关键:释放 recognizer
super.dispose();
}
}
```
---
## 五、踩坑记录
1. **`textScaleFactor` 已废弃**(Flutter 3.x)→ 用 `textScaler` / `MediaQuery.textScalerOf(context)`;
2. **`withOpacity` 已废弃** → 用 `withValues(alpha: x)`;
3. textAlign 不生效 = 没有宽度约束(用 stretch 或固定宽);
4. 截断不生效 = 没有 `maxLines`(三件套要配齐);
5. `TapGestureRecognizer` 不 dispose 会内存泄漏(页面反复进出后崩溃/卡顿)。
---
## 六、扩展思考
- 富文本进阶:本项目的 `RichTextContent`([rich_text_demo.md](rich_text_demo.md))渲染 HTML 富文本(题目/解析),
底层就是 TextSpan 体系的自动生成;
- 全局字体缩放:`MaterialApp(builder: ...)` 里统一包 `MediaQuery` 改造,实现"阅读字号调节"(见 rich_text_demo 的 Aa±);
- 文本选择:`SelectableText` 让用户可复制(本项目的日志区就用它)。