# 【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` 让用户可复制(本项目的日志区就用它)。