AtomGit Flutter鸿蒙客户端:主题系统

张开发
2026/6/10 1:36:11 15 分钟阅读

分享文章

AtomGit Flutter鸿蒙客户端:主题系统
设计理念遵循 Material 3项目采用 Material 3 的主题体系核心理念是从单一种子色生成完整的设计系统。Material 3 引入了基于 HCTHue-Chroma-Tone色调-色度-明度的颜色系统只需提供一个种子色框架会自动生成 Primary、Secondary、Tertiary、Error、Surface 五个颜色组每个组包含多个明度变体。AppTheme 类importpackage:flutter/material.dart;classAppTheme{staticconst_seedColorColor(0xFF1A73E8);// Google BluestaticThemeDatagetlight_buildTheme(Brightness.light);staticThemeDatagetdark_buildTheme(Brightness.dark);staticThemeData_buildTheme(Brightnessbrightness){finalcolorSchemeColorScheme.fromSeed(seedColor:_seedColor,brightness:brightness,);returnThemeData(colorScheme:colorScheme,useMaterial3:true,// 组件主题覆盖appBarTheme:constAppBarTheme(centerTitle:false,elevation:0,scrolledUnderElevation:1,),cardTheme:CardTheme(elevation:1,shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(12),),clipBehavior:Clip.antiAlias,),inputDecorationTheme:InputDecorationTheme(border:OutlineInputBorder(borderRadius:BorderRadius.circular(12),),contentPadding:constEdgeInsets.symmetric(horizontal:16,vertical:12,),isDense:true,),filledButtonTheme:FilledButtonThemeData(style:FilledButton.styleFrom(shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(8),),),),);}}种子色的选择#1A73E8Google Blue被选为种子色。这个颜色在蓝色系中具有良好的饱和度和对比度Material 3 的ColorScheme.fromSeed会基于它生成完整的调色板。如果后续需要更换品牌色只需修改这一个常量。Brightness 枚举的使用_buildTheme接收Brightness枚举并根据其值生成对应的 ColorScheme。Material 3 的ColorScheme.fromSeed在接收brightness: Brightness.dark时会自动调整所有颜色的明度——Primary 色会调亮以在深色背景上有足够对比度Surface 色会变暗。组件主题覆盖的详细说明全局的ThemeData是组件样式的最高优先级。通过ThemeData的组件属性覆盖可以确保应用中所有同类组件保持一致的视觉效果无需在每个使用点重复设置样式。AppBar 主题appBarTheme:constAppBarTheme(centerTitle:false,// 标题左对齐而非居中elevation:0,// 无阴影扁平设计scrolledUnderElevation:1,// 滚动时显示 1px 阴影),centerTitle: false是 Material 3 的默认值左对齐标题适合内容密度高的应用。scrolledUnderElevation: 1在用户滚动内容时在 AppBar 底部添加细微阴影提供视觉层次——内容滚动到 AppBar 下面时阴影分离了两者。Card 主题cardTheme:CardTheme(elevation:1,// 轻微阴影shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(12),// 12px 圆角),clipBehavior:Clip.antiAlias,// 抗锯齿裁剪),elevation: 1创建非常轻微的阴影——刚好能让 Card 从背景中浮出来但不会有 Material 2 那种厚重的投影感。12px 的圆角属于 Material 3 的中等圆角风格。clipBehavior: Clip.antiAlias确保 Card 的子 Widget 被裁剪到圆角边界内。没有这个设置子 Widget如 InkWell 的水波纹可能超出圆角范围产生视觉瑕疵。InputDecoration 主题inputDecorationTheme:InputDecorationTheme(border:OutlineInputBorder(borderRadius:BorderRadius.circular(12),),contentPadding:constEdgeInsets.symmetric(horizontal:16,vertical:12,),isDense:true,),OutlineInputBorder是 Material 3 推荐的输入框样式对比 Material 2 的 UnderlineInputBorder 线条样式。12px 圆角与 Card 保持一致。isDense: true减小输入框的默认高度适合移动端紧凑布局。FilledButton 主题filledButtonTheme:FilledButtonThemeData(style:FilledButton.styleFrom(shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(8),),),),FilledButton是 Material 3 的主要按钮样式使用 Primary 色填充。8px 圆角比 Card 的 12px 略小是 Material 3 按钮的推荐圆角值。在 MaterialApp 中使用主题classAtomGitAppextendsStatelessWidget{overrideWidgetbuild(BuildContextcontext){returnMultiProvider(providers:[...],child:MaterialApp(title:AtomGit,theme:AppTheme.light,darkTheme:AppTheme.dark,themeMode:ThemeMode.system,// 跟随系统设置home:constMainShell(),onGenerateRoute:AtomGitApp.generateRoute,),);}}themeMode: ThemeMode.system让主题自动跟随系统系统浅色模式 → AppTheme.light系统深色模式 → AppTheme.darkFlutter 在系统主题切换时会自动重建 MaterialApp无需应用代码手动处理。这是在ThemeData级别实现的——两个ThemeData对象中的颜色值不同MaterialApp 自动选择。组件中消费主题所有组件通过Theme.of(context)获取当前主题而不是硬编码颜色值// 获取主题色finalprimaryColorTheme.of(context).colorScheme.primary;// 获取错误色finalerrorColorTheme.of(context).colorScheme.error;// 获取 Surface 容器色代码块背景、头像占位finalcontainerColorTheme.of(context).colorScheme.surfaceContainerHighest;// 获取文字样式finaltitleStyleTheme.of(context).textTheme.titleMedium;finalbodyStyleTheme.of(context).textTheme.bodySmall;为什么不能硬编码颜色// 不好切换深色模式后文字不可见Text(Hello,style:TextStyle(color:Colors.black));// 好自动适配深色/浅色Text(Hello,style:TextStyle(color:Theme.of(context).colorScheme.onSurface));硬编码颜色只在一个主题下是正确的。Theme.of(context)获取的颜色是当前有效主题的值自动适配系统切换。ColorScheme 的关键令牌Material 3 的ColorScheme提供了丰富的颜色令牌。项目中使用频率最高的令牌浅色模式示例深色模式示例用途primary亮蓝淡蓝主题色用于按钮、选中态、Tab 指示器onPrimary白色深蓝黑Primary 色上的文字色primaryContainer淡蓝深蓝展示 primary 的背景容器onPrimaryContainer深蓝淡蓝容器上的文字色secondary蓝灰浅蓝灰次要元素FilterChiperror红色浅红错误状态图标和文字surface近白深灰页面背景surfaceContainerHighest浅灰深灰最突出的表面容器代码块背景onSurface深灰近黑近白主要文字色onSurfaceVariant中灰浅灰次要文字色Material 3 ColorScheme.fromSeed 的原理ColorScheme.fromSeed使用 Material 3 的 HCT 色彩系统输入一个种子色#1A73E8和一个亮度模式色调Hue分析从种子色提取色调值色度Chroma分配为 Primary 分配最高色度鲜艳Secondary 降低色度柔和Tertiary 取互补色调明度Tone调整根据 brightness 参数为每个颜色生成不同明度的变体对比度保证OnXxx颜色自动选择与对应Xxx色具有足够对比度的明度值满足 WCAG 无障碍标准深色模式的颜色适配Material 3 的深色模式不是简单地反转颜色而是精心调整色调和明度Primary 变淡在深色背景上primary变得更亮以确保对比度Surface 变暗背景色从浅灰变为深灰减少屏幕发光量Container 颜色反转浅色模式下 Container 是主色的淡化版白底上带淡色深色模式下 Container 是主色的加深版黑底上带暗色OnSurface 变亮文字色从深色变为浅色保证在暗背景上的可读性项目中不需要为深色模式写任何额外的颜色代码——所有颜色通过ColorScheme引用自动获得适配。API 常量和应用配置classApiConstants{staticconstStringbaseUrlhttps://api.atomgit.com/api/v5;staticconstStringauthorizeUrlhttps://api.atomgit.com/login/oauth/authorize;staticconstStringtokenUrlhttps://api.atomgit.com/login/oauth/access_token;staticconstStringredirectUriatomgit://oauth/callback;staticconstStringapiVersion2023-02-21;staticconstStringscoperepo user;staticconstint pageSize30;staticconstint rateLimitAuthenticated5000;staticconstint rateLimitUnauthenticated60;}API 相关常量集中在一个类中。这遵循单一数据源原则——如果 API 地址变更只需修改一处。主题扩展未来可以为应用添加应用内主题切换不依赖系统设置。实现思路enumAppThemeMode{light,dark,system}classThemeProviderextendsChangeNotifier{AppThemeMode_modeAppThemeMode.system;ThemeModegetthemeModeswitch(_mode){AppThemeMode.lightThemeMode.light,AppThemeMode.darkThemeMode.dark,AppThemeMode.systemThemeMode.system,};voidsetMode(AppThemeModemode){_modemode;notifyListeners();}}然后在MaterialApp中MaterialApp(themeMode:context.watchThemeProvider().themeMode,// ...)使用主题的最佳实践几个贯穿整个项目的主题使用原则永远使用Theme.of(context)不要缓存主题引用。系统主题切换时缓存的引用会过时。使用语义颜色令牌而非低级颜色值。colorScheme.error好于Colors.red因为 error 色在深色模式下会自动调节明度。使用textTheme的样式层级而非自定义 fontSize。textTheme.titleMedium好于fontSize: 16因为字体大小适配无障碍设置。Card 和 InputDecoration 的圆角保持一致12pxFilledButton 略小8px形成清晰的视觉层次。

更多文章