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