# 修复 UI 边界溢出与记分页白屏问题 ## 问题概述 1. **记分页白屏(严重)**:进入记分页后白屏,由 `OutlinedButton` 收到无限宽度约束导致整个 `Scaffold` 布局失败引起 2. **首页环值分布卡片溢出**:`score_distribution_card.dart:86` Column 底部溢出 13px 3. **创建页数字选择器溢出**:`point_book_create_page.dart:187` Row 右侧溢出 14px ## 根因分析 ### 白屏根因:`SizedBox(height: size)` 与 `Expanded` 的约束冲突 `point_book_edit_page.dart` 第 82-141 行的结构: ``` Expanded( // 给子节点 tight height = 剩余高度 (如 200px) child: Padding( child: LayoutBuilder( builder: (context, constraints) { final size = constraints.maxWidth; // 如 350px (屏幕宽度) return SizedBox( width: size, // 350 height: size, // 350 ← 与 Expanded 的 200px 冲突! child: GestureDetector(...), ); }, ), ), ) ``` **约束冲突原理**: - `Expanded` 给子节点 `BoxConstraints(minHeight: 200, maxHeight: 200)` (tight) - `SizedBox(height: 350)` 给子节点 `BoxConstraints(minHeight: 350, maxHeight: 350)` (tight) - 交集:`minHeight: max(200,350)=350, maxHeight: min(200,350)=200` → **350 > 200,不可能约束!** - 布局失败级联到整个 Column → Scaffold → 白屏 ### 环值分布卡片溢出根因 `score_distribution_card.dart` 第 84 行:`maxH = constraints.maxHeight - 28` 柱状图 `_Bar` 的 Column 内容总高度 = count文字(~15) + spacing(4) + bar(最大 maxH=112) + spacing(4) + label文字(~16) = 151px,但可用高度仅 140px,溢出 11-13px。 ### 创建页溢出根因 `point_book_create_page.dart` 第 187 行:`_NumberPicker` 内的 Row 包含两个默认尺寸 `IconButton`(各 48px)+ 文字 + 标签文字,在半屏宽度内放不下。 ## 修改方案 ### 1. `point_book_edit_page.dart` — 修复白屏(关键) **文件**:`lib/features/scoring/presentation/point_book_edit_page.dart` **行号**:82-141 将 `Expanded > Padding > LayoutBuilder > SizedBox` 结构改为 `Expanded > Padding > Center > AspectRatio > LayoutBuilder`: ```dart // 修改前(第 85-90 行): child: LayoutBuilder( builder: (context, constraints) { final size = constraints.maxWidth; return SizedBox( width: size, height: size, child: GestureDetector( // 修改后: child: Center( child: AspectRatio( aspectRatio: 1.0, child: LayoutBuilder( builder: (context, constraints) { final size = constraints.maxWidth; return GestureDetector( ``` 关键变更: - 在 `Padding` 和 `LayoutBuilder` 之间插入 `Center(child: AspectRatio(aspectRatio: 1.0))` - 删除 `SizedBox(width: size, height: size)` 包装层 - `Center` 松解 `Expanded` 的 tight height 约束 → `AspectRatio` 计算 min(宽,高) 的正方形 → `LayoutBuilder` 获取的 `constraints.maxWidth == constraints.maxHeight` → 无冲突 - `Image.asset` 和 `CustomPaint` 的 `size: Size(size, size)` 保持不变 - 对应关闭括号:需要增加 `),` (AspectRatio) 和 `),` (Center) 的闭合 ### 2. `point_book_create_page.dart` — 修复 Row 溢出 14px **文件**:`lib/features/scoring/presentation/point_book_create_page.dart` **行号**:187-216(`_NumberPicker` 的 build 方法) 修改 `_NumberPicker` 中的两个 `IconButton`,使其更紧凑: ```dart // 修改前(第 193-198 行): IconButton( icon: const Icon(Icons.remove_circle_outline), onPressed: () { // 修改后: IconButton( icon: const Icon(Icons.remove_circle_outline), iconSize: 20, visualDensity: VisualDensity.compact, padding: EdgeInsets.zero, constraints: const BoxConstraints(), onPressed: () { ``` 同样修改 `add` 按钮(第 207-211 行)。 并将标签文字包裹 `Flexible`(第 190 行): ```dart // 修改前: Text(label, style: const TextStyle(fontSize: 13)), // 修改后: Flexible( child: Text(label, style: const TextStyle(fontSize: 13)), ), ``` ### 3. `score_distribution_card.dart` — 修复 Column 溢出 13px **文件**:`lib/features/home/presentation/widgets/score_distribution_card.dart` **行号**:第 84 行 ```dart // 修改前: final maxH = constraints.maxHeight - 28; // reserve space for label // 修改后: final maxH = constraints.maxHeight - 40; // reserve space for count + label ``` 将预留空间从 28px 增加到 40px,确保柱子最大高度不会导致 Column 溢出。 ### 4. `heatmap_card.dart` — 修复 CustomPaint 尺寸为零(附带修复) **文件**:`lib/features/home/presentation/widgets/heatmap_card.dart` **行号**:第 29 行 当前 `Stack` 中 `CustomPaint` 没有指定 `size`,在 `Stack` 中默认尺寸为 0x0,导致命中点不可见。 ```dart // 修改前(第 29 行): child: Stack( alignment: Alignment.center, children: [ // 修改后: child: Stack( fit: StackFit.expand, alignment: Alignment.center, children: [ ``` 添加 `fit: StackFit.expand` 使所有非定位子节点(`Image.asset` 和 `CustomPaint`)填满 Stack。 ## 验证步骤 1. 运行 `flutter analyze` 确认无错误 2. 启动 APP,进入首页 → 确认无黄色溢出条纹 3. 点击"开始记分" → 进入创建页 → 确认数字选择器无溢出 4. 完成创建 → 进入记分页 → 确认 **不白屏**,靶面正常显示 5. 点击靶面 → 确认命中点准确渲染 6. 返回首页 → 查看热力图 → 确认命中点可见