# 视觉统一 — 实施文档 > 对照《页面设计文档》规范,逐项统一圆角、阴影、留白、颜色。 ## 一、设计 Token 集中化 在 `AppTheme` 中新增静态 Token,所有组件从 Token 取值,不再硬编码: ```dart class AppTheme { // ── 已有(不动)── static const Color primary = Color(0xFF8B9CF7); static const Color primaryLight = Color(0xFFF0F2FF); static const Color bg = Color(0xFFF8F9FC); static const Color surface = Color(0xFFFFFFFF); static const Color text = Color(0xFF2D2B32); static const Color textSub = Color(0xFF8A8892); static const Color textHint = Color(0xFFBFBCC4); static const Color success = Color(0xFF6ECF8A); static const Color error = Color(0xFFF56C6C); static const Color warning = Color(0xFFF5A623); // ── 新增:圆角 Token ── static const double radiusXs = 8; // 标签、小徽章 static const double radiusSm = 12; // 输入框、小按钮 static const double radiusMd = 16; // 列表项、菜单、弹窗内卡片 static const double radiusLg = 20; // 按钮 static const double radiusXl = 24; // 主卡片 static const double radiusPill = 999; // 胶囊 // ── 新增:间距 Token ── static const double spaceXs = 4; static const double spaceSm = 8; static const double spaceMd = 12; static const double spaceLg = 16; static const double spaceXl = 20; static const double space2xl = 24; // ── 新增:阴影 Token ── static BoxShadow shadowCard = BoxShadow( color: primary.withAlpha(15), blurRadius: 12, offset: const Offset(0, 4), ); static BoxShadow shadowBubble = BoxShadow( color: primary.withAlpha(12), blurRadius: 10, offset: const Offset(0, 3), ); static BoxShadow shadowNone = const BoxShadow( color: Colors.transparent, blurRadius: 0, offset: Offset.zero, ); } ``` ## 二、ThemeData 统一调整 ```dart static ThemeData get lightTheme => ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: primary, primary: primary, surface: bg, brightness: Brightness.light), scaffoldBackgroundColor: bg, // ── AppBar ── 不变 appBarTheme: const AppBarTheme( backgroundColor: surface, foregroundColor: text, elevation: 0, centerTitle: true, scrolledUnderElevation: 0, titleTextStyle: TextStyle( fontSize: 17, fontWeight: FontWeight.w600, color: text), ), // ── Card: radius 16 → 24 ── cardTheme: CardThemeData( color: surface, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(radiusXl)), // 24 margin: EdgeInsets.zero, ), // ── Input: radius 12 → 16, 内边距增加 ── inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: const Color(0xFFF4F5FA), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 14), // 更宽松 border: OutlineInputBorder( borderRadius: BorderRadius.circular(radiusMd), // 16 borderSide: BorderSide.none), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(radiusMd), borderSide: BorderSide.none), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(radiusMd), borderSide: const BorderSide(color: primary, width: 1.5)), hintStyle: const TextStyle(color: textHint, fontSize: 15), ), // ── Button: radius 14 → 20, 高度 48 → 52 ── elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: primary, foregroundColor: Colors.white, minimumSize: const Size(double.infinity, 52), // 更高 shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(radiusLg)), // 20 textStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600), elevation: 0, ), ), // ── Dialog: radius 保持 22,略增 ── dialogTheme: DialogThemeData( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(radiusXl)), // 24 ), // BottomSheet 主题 bottomSheetTheme: const BottomSheetThemeData( shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical( top: Radius.circular(radiusXl))), // 24 ), // 文字主题(不动) textTheme: const TextTheme(...), ); ``` ## 三、逐文件硬编码替换 ### 3.1 health_drawer.dart ```dart // 找:BorderRadius.circular(16) // 替换:BorderRadius.circular(AppTheme.radiusXl) → 24 // _SectionCard decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppTheme.radiusXl), // was 16 boxShadow: [AppTheme.shadowCard], // 统一 ) // _MetricTile decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppTheme.radiusMd), // was 10 ) // _FeatureChip decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppTheme.radiusMd), // was 12 ) // _ConversationItem decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppTheme.radiusSm), // was 10 ) ``` ### 3.2 chat_messages_view.dart ```dart // AI 气泡 — 不动(radius 20 符合规范) // 用户气泡 — 不动 // 按钮卡片 — 统一 // _cardFilledBtn shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppTheme.radiusLg)), // was 12 // _cardOutlineBtn shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppTheme.radiusLg)), // was 12 // DataConfirmCard 外层 borderRadius: BorderRadius.circular(AppTheme.radiusXl), // was 20 // 内部小卡片 borderRadius: BorderRadius.circular(AppTheme.radiusMd), // was 10-14 // 快捷选项按钮 borderRadius: BorderRadius.circular(AppTheme.radiusPill), // was 20 ``` ### 3.3 medication 相关页面 ```dart // medication_list_page.dart / medication_edit_page.dart // 列表项卡片: was 12-16 → AppTheme.radiusMd (16) // 按钮: was 14 → AppTheme.radiusLg (20) ``` ### 3.4 remaining_pages.dart ```dart // HealthCalendarPage 日期格子 borderRadius: BorderRadius.circular(AppTheme.radiusXs), // was 20(错误值) // ExercisePlanPage 进度卡片 borderRadius: BorderRadius.circular(AppTheme.radiusXl), // was 20 // ExercisePlanItem 日条目 borderRadius: BorderRadius.circular(AppTheme.radiusMd), // was 16 // FollowUpItem 随访卡片 borderRadius: BorderRadius.circular(AppTheme.radiusXl), // was 16 ``` ### 3.5 diet_capture_page.dart ```dart // 拍照大圆 borderRadius: BorderRadius.circular(90), // 不动 // 食物列表容器 borderRadius: BorderRadius.circular(AppTheme.radiusXl), // was 20 // 食物条目 borderRadius: BorderRadius.circular(AppTheme.radiusMd), // was 16 // 按钮 borderRadius: BorderRadius.circular(AppTheme.radiusPill), // was 24 ``` ### 3.6 report/consultation 等页面 ```dart // 搜索替换:BorderRadius.circular(12) → AppTheme.radiusSm // 搜索替换:BorderRadius.circular(16) → AppTheme.radiusMd // 卡片外框:→ AppTheme.radiusXl // 按钮:→ AppTheme.radiusLg ``` ## 四、阴影统一 全局替换: ```dart // 旧:boxShadow: [BoxShadow(color: Color(0xFF8B9CF7).withAlpha(15), blurRadius: 14, offset: Offset(0, 4))] // 新:boxShadow: [AppTheme.shadowCard] // 旧:boxShadow: [BoxShadow(color: Color(0xFF8B9CF7).withAlpha(12), blurRadius: 10, offset: Offset(0, 3))] // 新:boxShadow: [AppTheme.shadowBubble] ``` ## 五、替换策略 | 原值 | Token | 用于 | |------|-------|------| | 8 | `radiusXs` | 标签、小圆点、Chip | | 10-12 | `radiusSm` | 输入框、列表项、小图标容器 | | 14-16 | `radiusMd` | 弹窗内部卡片、指标方块、食物条目 | | 18-20 | `radiusLg` | 按钮 | | 24+ | `radiusXl` | 主卡片、抽屉分区、对话框 | | 999 | `radiusPill` | 胶囊按钮、快捷选项 | ## 六、验证方式 改完后跑 `flutter analyze` 确认无错误,然后运行 App 目测以下页面: 1. 侧滑抽屉 — 卡片圆角、阴影 2. 首页对话 — 气泡、按钮、任务卡片 3. 拍饮食 — 识别结果卡片、按钮 4. 登录页 — 输入框、按钮 5. 运动计划 — 日条目、进度卡片 ## 七、文件改动清单 ``` 修改: lib/core/app_theme.dart (+ 圆角/间距/阴影 Token, ThemeData 调整, ~50行) lib/widgets/health_drawer.dart (~15处硬编码替换) lib/pages/home/widgets/chat_messages_view.dart (~20处硬编码替换) lib/pages/diet/diet_capture_page.dart (~8处硬编码替换) lib/pages/auth/login_page.dart (~5处硬编码替换) lib/pages/remaining_pages.dart (~10处硬编码替换) lib/pages/medication/medication_list_page.dart (~5处硬编码替换) lib/pages/medication/medication_edit_page.dart (~3处硬编码替换) lib/pages/report/report_pages.dart (~5处硬编码替换) lib/pages/report/ai_analysis_page.dart (~3处硬编码替换) lib/pages/settings/*.dart (~3处硬编码替换) lib/pages/profile/*.dart (~5处硬编码替换) ``` 改动虽然文件多,但每个文件都是纯替换——把数字换成 AppTheme Token,**不涉及逻辑变更**。 ## 八、不做的事情 - 不改变颜色体系(淡薰紫主题保持) - 不改变字体/字号 - 不改变布局结构 - 不引入新的 UI 组件