merge: 稳定二级标签切换布局
This commit is contained in:
commit
62cb4d9809
4 files changed
+33
-37
No files matched your search
@@ -1111,7 +1111,7 @@ $ flutter test
|
|||||||
|
|
||||||
## 2026-10-22 首页布局对齐修正
|
## 2026-10-22 首页布局对齐修正
|
||||||
|
|
||||||
- 一级分类未选 18/w400、选中 20/w700;二级 chips 与 26 高透明三线筛选图标仅在精选显示。
|
- 一级分类未选 18/w400、选中 20/w700;二级 chips 间距 24、15/w600,并以稳定 AnimatedContainer 切换。
|
||||||
- 四类卡片去底板/描边,封面统一 3:4、8 圆角、行距 10、封底标题间距 6;状态角标为右上角紧凑异形丝带。
|
- 四类卡片去底板/描边,封面统一 3:4、8 圆角、行距 10、封底标题间距 6;状态角标为右上角紧凑异形丝带。
|
||||||
- 标题下方恢复左对齐题材文字,使用 `|` 分隔、灰色小字,与封面状态角标保持独立。
|
- 标题下方恢复左对齐题材文字,使用 `|` 分隔、灰色小字,与封面状态角标保持独立。
|
||||||
- 首页搜索栏到一级、一级到二级、二级到网格间距为 8/8/10;非精选 tab 直接以 10 衔接网格。
|
- 首页搜索栏到一级、一级到二级、二级到网格间距为 8/8/10;非精选 tab 直接以 10 衔接网格。
|
||||||
|
|||||||
@@ -111,12 +111,15 @@ abstract final class AppDimens {
|
|||||||
static const double homeSecondaryTagHeight = 26;
|
static const double homeSecondaryTagHeight = 26;
|
||||||
static const double homeSecondaryTagHorizontalPadding = 10;
|
static const double homeSecondaryTagHorizontalPadding = 10;
|
||||||
static const double homeSecondaryTagRadius = 13;
|
static const double homeSecondaryTagRadius = 13;
|
||||||
|
static const Duration homeSecondaryTagAnimationDuration = Duration(
|
||||||
|
milliseconds: 150,
|
||||||
|
);
|
||||||
static const double homeSecondaryFilterGap = 8;
|
static const double homeSecondaryFilterGap = 8;
|
||||||
static const double homeSecondaryFilterVisualSize = 26;
|
static const double homeSecondaryFilterVisualSize = 26;
|
||||||
static const double homeSecondaryFilterIcon = 16;
|
static const double homeSecondaryFilterIcon = 16;
|
||||||
static const double homeSecondaryFilterStroke = 1.7;
|
static const double homeSecondaryFilterStroke = 1.7;
|
||||||
static const double homePrimaryCategoryGap = 24;
|
static const double homePrimaryCategoryGap = 24;
|
||||||
static const double homeSecondaryTagGap = 14;
|
static const double homeSecondaryTagGap = 24;
|
||||||
static const double homeSearchTopGap = 0;
|
static const double homeSearchTopGap = 0;
|
||||||
static const double homeSearchPrimaryGap = 8;
|
static const double homeSearchPrimaryGap = 8;
|
||||||
static const double homePrimarySecondaryGap = 8;
|
static const double homePrimarySecondaryGap = 8;
|
||||||
|
|||||||
@@ -366,10 +366,10 @@ class HomeGridHeader extends StatelessWidget {
|
|||||||
final selected = selectedTag == tag.id;
|
final selected = selectedTag == tag.id;
|
||||||
final label = Text(
|
final label = Text(
|
||||||
tag.label,
|
tag.label,
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
color: selected ? AppColors.navSelected : AppColors.textTertiary,
|
color: selected ? AppColors.navSelected : AppColors.textTertiary,
|
||||||
fontSize: AppDimens.homeSecondaryTagFont,
|
fontSize: AppDimens.homeSecondaryTagFont,
|
||||||
fontWeight: selected ? FontWeight.w600 : FontWeight.w400,
|
fontWeight: FontWeight.w600,
|
||||||
letterSpacing: 0,
|
letterSpacing: 0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -377,25 +377,21 @@ class HomeGridHeader extends StatelessWidget {
|
|||||||
key: Key('home-tag-${tag.id}'),
|
key: Key('home-tag-${tag.id}'),
|
||||||
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
||||||
onTap: () => onTagSelected(selected ? null : tag.id),
|
onTap: () => onTagSelected(selected ? null : tag.id),
|
||||||
child: selected
|
child: AnimatedContainer(
|
||||||
? Container(
|
key: Key('home-tag-animated-${tag.id}'),
|
||||||
height: AppDimens.homeSecondaryTagHeight,
|
duration: AppDimens.homeSecondaryTagAnimationDuration,
|
||||||
padding: const EdgeInsets.symmetric(
|
curve: Curves.easeOut,
|
||||||
horizontal: AppDimens.homeSecondaryTagHorizontalPadding,
|
height: AppDimens.homeSecondaryTagHeight,
|
||||||
),
|
padding: const EdgeInsets.symmetric(
|
||||||
alignment: Alignment.center,
|
horizontal: AppDimens.homeSecondaryTagHorizontalPadding,
|
||||||
decoration: BoxDecoration(
|
),
|
||||||
color: AppColors.contentSurface,
|
alignment: Alignment.center,
|
||||||
borderRadius: BorderRadius.circular(
|
decoration: BoxDecoration(
|
||||||
AppDimens.homeSecondaryTagRadius,
|
color: selected ? AppColors.contentSurface : AppColors.transparent,
|
||||||
),
|
borderRadius: BorderRadius.circular(AppDimens.homeSecondaryTagRadius),
|
||||||
),
|
),
|
||||||
child: label,
|
child: label,
|
||||||
)
|
),
|
||||||
: SizedBox(
|
|
||||||
height: AppDimens.homeSecondaryTagHeight,
|
|
||||||
child: Align(alignment: Alignment.centerLeft, child: label),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,14 +167,14 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(secondaryTag.style?.fontSize, AppDimens.homeSecondaryTagFont);
|
expect(secondaryTag.style?.fontSize, AppDimens.homeSecondaryTagFont);
|
||||||
expect(secondaryTag.style?.fontWeight, FontWeight.w400);
|
expect(secondaryTag.style?.fontWeight, FontWeight.w600);
|
||||||
expect(secondaryTag.style?.color, AppColors.textTertiary);
|
expect(secondaryTag.style?.color, AppColors.textTertiary);
|
||||||
|
final unselectedTagChip = tester.widget<AnimatedContainer>(
|
||||||
|
find.byKey(const Key('home-tag-animated-hot')),
|
||||||
|
);
|
||||||
expect(
|
expect(
|
||||||
find.descendant(
|
(unselectedTagChip.decoration! as BoxDecoration).color,
|
||||||
of: find.byKey(const Key('home-tag-hot')),
|
AppColors.transparent,
|
||||||
matching: find.byType(Container),
|
|
||||||
),
|
|
||||||
findsNothing,
|
|
||||||
);
|
);
|
||||||
final primaryStart = tester.getTopLeft(find.text('Featured'));
|
final primaryStart = tester.getTopLeft(find.text('Featured'));
|
||||||
final pageStart = tester.getTopLeft(searchBox);
|
final pageStart = tester.getTopLeft(searchBox);
|
||||||
@@ -183,23 +183,20 @@ void main() {
|
|||||||
tester.getTopLeft(find.text('New')).dx -
|
tester.getTopLeft(find.text('New')).dx -
|
||||||
tester.getBottomRight(find.text('Featured')).dx;
|
tester.getBottomRight(find.text('Featured')).dx;
|
||||||
expect(primaryGap, closeTo(AppDimens.homePrimaryCategoryGap, 0.1));
|
expect(primaryGap, closeTo(AppDimens.homePrimaryCategoryGap, 0.1));
|
||||||
final tagStart = tester.getTopLeft(find.text('Hot'));
|
final tagStart = tester.getTopLeft(find.byKey(const Key('home-tag-hot')));
|
||||||
expect(tagStart.dx, pageStart.dx);
|
expect(tagStart.dx, pageStart.dx);
|
||||||
expect(
|
expect(
|
||||||
tester.getSize(find.byKey(const Key('home-tag-hot'))).height,
|
tester.getSize(find.byKey(const Key('home-tag-hot'))).height,
|
||||||
AppDimens.homeSecondaryTagHeight,
|
AppDimens.homeSecondaryTagHeight,
|
||||||
);
|
);
|
||||||
final tagGap =
|
final tagGap =
|
||||||
tester.getTopLeft(find.text('Uplifting')).dx -
|
tester.getTopLeft(find.byKey(const Key('home-tag-uplifting'))).dx -
|
||||||
tester.getBottomRight(find.text('Hot')).dx;
|
tester.getBottomRight(find.byKey(const Key('home-tag-hot'))).dx;
|
||||||
expect(tagGap, closeTo(AppDimens.homeSecondaryTagGap, 0.1));
|
expect(tagGap, closeTo(AppDimens.homeSecondaryTagGap, 0.1));
|
||||||
await tester.tap(find.byKey(const Key('home-tag-hot')));
|
await tester.tap(find.byKey(const Key('home-tag-hot')));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
final selectedTagChip = tester.widget<Container>(
|
final selectedTagChip = tester.widget<AnimatedContainer>(
|
||||||
find.descendant(
|
find.byKey(const Key('home-tag-animated-hot')),
|
||||||
of: find.byKey(const Key('home-tag-hot')),
|
|
||||||
matching: find.byType(Container),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
(selectedTagChip.decoration! as BoxDecoration).color,
|
(selectedTagChip.decoration! as BoxDecoration).color,
|
||||||
|
|||||||
Reference in new issue
Block a user