merge: 稳定二级标签切换布局

This commit is contained in:
Zhou Weidong committed 2026-10-22 18:41:05 +08:00
commit 62cb4d9809
4 files changed
+33 -37

No files matched your search

+1 -1
View File
@@ -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 衔接网格。
+4 -1
View File
@@ -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;
+17 -21
View File
@@ -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),
),
); );
} }
} }
+11 -14
View File
@@ -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,