| name | widget-size-checklist |
| description | 确保小组件组件根据 HomeWidgetSize 正确调整各元素大小,包括容器、图标、字体、间距、线条粗细等 |
Widget Size Checklist - 小组件大小自检清单
确保小组件组件根据 HomeWidgetSize 正确调整各元素大小。
Usage
/widget-size-checklist <widget_file_path>
/widget-size-checklist lib/screens/widgets_gallery/common_widgets/widgets/circular_metrics_card.dart
HomeWidgetSize 常用方法速查
尺寸和布局方法
| 方法 | 说明 | Small | Medium | Large | Wide | Wide2 |
|---|
getPadding() | 外层容器内边距 | 8px | 12px | 16px | 12px | 16px |
getTitleSpacing() | 标题与内容间距 | 16px | 20px | 24px | 20px | 24px |
getItemSpacing() | 列表项之间间距 | 6px | 8px | 12px | 8px | 12px |
getSmallSpacing() | 紧密元素间距 | 2px | 4px | 6px | 4px | 6px |
getHeightConstraints() | 高度约束 | 150-250 | 200-350 | 250-450 | 200-350 | 250-450 |
字体大小方法
| 方法 | 说明 | Small | Medium | Large | Wide | Wide2 |
|---|
getLargeFontSize() | 大标题/数值 | 36px | 48px | 56px | 48px | 56px |
getTitleFontSize() | 标题 | 16px | 24px | 28px | 24px | 28px |
getSubtitleFontSize() | 副标题/标签 | 12px | 14px | 16px | 14px | 16px |
getLegendFontSize() | 图例/小字 | 10px | 12px | 14px | 12px | 14px |
图形元素方法
| 方法 | 说明 | Small | Medium | Large | Wide | Wide2 |
|---|
getIconSize() | 图标大小 | 18px | 24px | 28px | 24px | 28px |
getStrokeWidth() | 线条粗细 | 6px | 8px | 10px | 8px | 10px |
getLegendIndicatorWidth() | 指示器宽度 | 16px | 24px | 32px | 24px | 32px |
getLegendIndicatorHeight() | 指示器高度 | 8px | 12px | 16px | 12px | 16px |
getBarWidth() | 柱状图柱宽 | 12px | 16px | 20px | 16px | 20px |
getBarSpacing() | 柱间距 | 0.5px | 1px | 1.5px | 1px | 1.5px |
缩放系数(可直接使用)
| 系数 | 默认值 | 用途 |
|---|
iconContainerScale | 2.0 | 图标容器大小 = 图标大小 × 2 |
progressStrokeScale | 0.4 | 进度条粗细 = strokeWidth × 0.4 |
Checklist
1. 组件参数检查
class MyWidget extends StatefulWidget {
final HomeWidgetSize size;
const MyWidget({
super.key,
required this.data,
this.size = const MediumSize(), // 默认值
});
factory MyWidget.fromProps(
Map<String, dynamic> props,
HomeWidgetSize size,
) {
return MyWidget(
data: props['data'],
size: size, // 必须传递
);
}
}
2. 外层容器检查
Container(
padding: widget.size.getPadding(),
constraints: widget.size.getHeightConstraints(),
decoration: BoxDecoration(...),
child: Column(
children: [
Text('标题', style: TextStyle(fontSize: widget.size.getTitleFontSize())),
SizedBox(height: widget.size.getTitleSpacing()),
// 内容
],
),
)
3. 子组件传递检查
// 列表项
_MyItemWidget(
data: item,
size: widget.size, // 必须传递
)
4. 内部元素大小检查
容器大小
final iconSize = size.getIconSize();
final containerSize = iconSize * size.iconContainerScale;
SizedBox(
width: containerSize,
height: containerSize,
child: ...
)
图标大小
Icon(
Icons.star,
size: size.getIconSize() * 0.8, // 可根据需要调整倍数
color: Colors.amber,
)
字体大小
Text(
'大数值',
style: TextStyle(
fontSize: size.getLargeFontSize() * 0.35, // 约 13-20px
fontWeight: FontWeight.w700,
),
),
SizedBox(height: size.getSmallSpacing()),
Text(
'标签',
style: TextStyle(
fontSize: size.getSubtitleFontSize(),
fontWeight: FontWeight.w500,
),
)
间距
SizedBox(width: size.getSmallSpacing() * 2), // 行间距
SizedBox(height: size.getSmallSpacing()), // 列间距
5. CustomPainter 检查
class _MyPainter extends CustomPainter {
final double strokeWidth;
_MyPainter({this.strokeWidth = 2.5});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..strokeWidth = strokeWidth // 使用参数
..style = PaintingStyle.stroke;
// ...
}
@override
bool shouldRepaint(covariant _MyPainter oldDelegate) {
return oldDelegate.strokeWidth != strokeWidth; // 检查变化
}
}
// 使用
CustomPaint(
painter: _MyPainter(
strokeWidth: widget.size.getStrokeWidth() * widget.size.progressStrokeScale,
),
child: ...
)
6. 示例文件检查
import 'package:Memento/screens/home_screen/models/home_widget_size.dart';
// 小尺寸
MyWidget(data: data, size: const SmallSize()),
// 中尺寸
MyWidget(data: data, size: const MediumSize()),
// 大尺寸
MyWidget(data: data, size: const LargeSize()),
// 中宽尺寸 (4x1) - 宽度填满屏幕
SizedBox(
width: MediaQuery.of(context).size.width - 32,
height: 220,
child: MyWidget(data: data, size: const WideSize()),
),
// 大宽尺寸 (4x2) - 宽度填满屏幕
SizedBox(
width: MediaQuery.of(context).size.width - 32,
height: 320,
child: MyWidget(data: data, size: const Wide2Size()),
),
Common Pitfalls
1. 子组件未接收 size 参数
// ❌ 错误
_MyItemWidget(data: item) // 缺少 size
// ✅ 正确
_MyItemWidget(data: item, size: widget.size)
2. 使用固定值而非 size 方法
// ❌ 错误
SizedBox(width: 56, height: 56)
// ✅ 正确
final containerSize = size.getIconSize() * size.iconContainerScale;
SizedBox(width: containerSize, height: containerSize)
3. CustomPainter 硬编码 strokeWidth
// ❌ 错误
backgroundPaint.strokeWidth = 2.5
// ✅ 正确
backgroundPaint.strokeWidth = strokeWidth
4. 字体大小固定
// ❌ 错误
fontSize: 16
// ✅ 正确
fontSize: size.getLargeFontSize() * 0.35
5. 示例文件未传递 size
// ❌ 错误 - 所有卡片都使用默认 MediumSize()
MyWidget(data: data)
// ✅ 正确 - 传递所有尺寸
MyWidget(data: data, size: const SmallSize())
MyWidget(data: data, size: const MediumSize())
MyWidget(data: data, size: const LargeSize())
MyWidget(data: data, size: const WideSize())
MyWidget(data: data, size: const Wide2Size())
Quick Fix Template
添加 size 参数到子组件
// 1. 添加参数
class _MyItemWidget extends StatelessWidget {
final MyData data;
final HomeWidgetSize size; // 添加
const _MyItemWidget({
required this.data,
required this.size, // 添加
});
// 2. 使用 size 计算尺寸
@override
Widget build(BuildContext context) {
final iconSize = size.getIconSize();
final valueFontSize = size.getLargeFontSize() * 0.35;
final labelFontSize = size.getSubtitleFontSize();
final spacing = size.getSmallSpacing();
// 3. 应用尺寸
return Row(
children: [
Icon(Icons.star, size: iconSize),
SizedBox(width: spacing),
Text('值', style: TextStyle(fontSize: valueFontSize)),
],
);
}
}
更新 CustomPainter
// 1. 添加参数
class _MyPainter extends CustomPainter {
final double progress;
final double strokeWidth; // 添加
_MyPainter({required this.progress, this.strokeWidth = 2.5});
// 2. 使用 strokeWidth
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..strokeWidth = strokeWidth // 使用参数
..style = PaintingStyle.stroke;
// ...
}
// 3. 检查 strokeWidth 变化
@override
bool shouldRepaint(covariant _MyPainter oldDelegate) {
return oldDelegate.progress != progress ||
oldDelegate.strokeWidth != strokeWidth;
}
}
Size Calculation Reference
环形进度条组件尺寸计算
// 图标大小
final iconSize = size.getIconSize(); // 18/24/28
// 容器大小
final containerSize = iconSize * size.iconContainerScale; // 36/48/56
// 进度条粗细
final strokeWidth = size.getStrokeWidth() * size.progressStrokeScale; // 2.4/3.2/4.0
// 数值字体
final valueFontSize = size.getLargeFontSize() * 0.35; // ~13/17/20
// 标签字体的
final labelFontSize = size.getSubtitleFontSize(); // 12/14/16
// 元素间距
final itemSpacing = size.getSmallSpacing() * 2; // 4/8/12
Testing Checklist
测试时确认以下内容: