Files
arcx-app/.trae/documents/fix-ui-layout-overflow-and-white-screen.md

5.9 KiB
Raw Permalink Blame History

修复 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)=200350 > 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

// 修改前(第 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(

关键变更:

  • PaddingLayoutBuilder 之间插入 Center(child: AspectRatio(aspectRatio: 1.0))
  • 删除 SizedBox(width: size, height: size) 包装层
  • Center 松解 Expanded 的 tight height 约束 → AspectRatio 计算 min(宽,高) 的正方形 → LayoutBuilder 获取的 constraints.maxWidth == constraints.maxHeight → 无冲突
  • Image.assetCustomPaintsize: 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,使其更紧凑:

// 修改前(第 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 行):

// 修改前:
          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 行

// 修改前:
        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 行

当前 StackCustomPaint 没有指定 size,在 Stack 中默认尺寸为 0x0,导致命中点不可见。

// 修改前(第 29 行):
                child: Stack(
                  alignment: Alignment.center,
                  children: [

// 修改后:
                child: Stack(
                  fit: StackFit.expand,
                  alignment: Alignment.center,
                  children: [

添加 fit: StackFit.expand 使所有非定位子节点(Image.assetCustomPaint)填满 Stack。

验证步骤

  1. 运行 flutter analyze 确认无错误
  2. 启动 APP,进入首页 → 确认无黄色溢出条纹
  3. 点击"开始记分" → 进入创建页 → 确认数字选择器无溢出
  4. 完成创建 → 进入记分页 → 确认 不白屏,靶面正常显示
  5. 点击靶面 → 确认命中点准确渲染
  6. 返回首页 → 查看热力图 → 确认命中点可见