欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netFlutter Dark Mode 在 OpenHarmony 系统中的适配实践前言最近在做 Flutter for OpenHarmony 项目时深色模式适配这块花的时间比我预想中要多。一开始我以为Flutter 本身已经支持 ThemeMode 了适配暗黑模式应该不复杂。结果真正接入 OpenHarmony 真机之后还是遇到了一堆细节问题。包括系统深色模式切换后页面不更新部分组件颜色异常状态栏颜色不统一页面切换时闪白图片资源不适配暗色主题尤其是多个页面叠加后颜色管理会越来越乱。后面我重新整理了一套主题管理方案整体体验才稳定下来。这篇文章主要记录一下我这次在 OpenHarmony 项目里的 Dark Mode 适配过程。一、为什么现在必须适配 Dark Mode现在大部分系统都已经默认支持深色模式。包括AndroidiOSOpenHarmony如果应用完全不适配用户体验会比较割裂。尤其晚上使用时亮白页面会特别突兀。我项目里的实际场景当前项目包括首页商品列表IM 聊天用户中心WebView 页面很多页面一开始都是直接写死颜色Container( color: Colors.white, )结果系统切暗黑模式后页面直接“半黑半白”。二、Flutter ThemeMode 基础接入Flutter 本身已经提供了主题切换方案。MaterialApp 配置MaterialApp( theme: lightTheme, darkTheme: darkTheme, themeMode: ThemeMode.system, )这里ThemeMode.system表示跟随系统主题。三、浅色主题与深色主题拆分后面我把所有主题单独拆了。light_theme.dartfinal ThemeData lightTheme ThemeData( brightness: Brightness.light, scaffoldBackgroundColor: Colors.white, appBarTheme: const AppBarTheme( backgroundColor: Colors.white, ), );dark_theme.dartfinal ThemeData darkTheme ThemeData( brightness: Brightness.dark, scaffoldBackgroundColor: Colors.black, appBarTheme: const AppBarTheme( backgroundColor: Colors.black, ), );这样后面维护会轻松很多。四、不要直接写死颜色这个是我这次适配里踩得最多的坑。之前的代码Text( 用户信息, style: TextStyle( color: Colors.black, ), )暗黑模式下文字直接看不见。后来的方案统一改成Text( 用户信息, style: TextStyle( color: Theme.of(context) .colorScheme .onBackground, ), )或者Theme.of(context).textTheme统一从主题读取颜色。后面适配会轻松很多。五、OpenHarmony 上的一个实际问题这个问题我在鸿蒙真机上复现得挺明显。问题现象系统已经切成暗黑模式。但 Flutter 页面没有实时更新。需要重启应用或重新进入页面主题才生效。后来的处理方式监听页面亮度变化。WidgetsBindingObserver监听didChangePlatformBrightness()override void didChangePlatformBrightness() { final brightness WidgetsBinding.instance .platformDispatcher .platformBrightness; print(brightness); }然后主动更新 ThemeMode。这个在 OpenHarmony 上会稳定很多。六、状态栏颜色适配这个问题很多人容易忽略。问题页面已经切暗色。但状态栏还是黑字。结果顶部直接看不清。解决方案SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.light, ), );浅色模式Brightness.dark深色模式Brightness.light这个在 OpenHarmony 真机里效果挺明显。七、图片资源适配这个也是后面项目里很容易出问题的地方。问题深色模式下原本的黑色图标直接“消失”。例如返回按钮tab 图标功能按钮后来的方案分别维护icon_dark.png icon_light.png根据主题切换。isDark ? dark/icon.png : light/icon.png虽然麻烦一点。但实际效果会好很多。八、页面切换闪白问题这个问题在 OpenHarmony 上我复现概率挺高。问题现象暗黑模式下页面 push/pop 时偶发白色闪屏。原因部分页面Scaffold背景色没配置。Flutter 默认会使用浅色背景。解决方式统一配置scaffoldBackgroundColor同时页面不要直接Container(color: Colors.white)这个优化后闪白问题减少很多。九、Provider 管理主题状态后面我把主题统一放到了 Provider。ThemeProviderclass ThemeProvider extends ChangeNotifier { ThemeMode themeMode ThemeMode.system; void changeTheme( ThemeMode mode) { themeMode mode; notifyListeners(); } }页面切换context .readThemeProvider() .changeTheme( ThemeMode.dark, );后面设置页系统跟随手动切换都方便很多。十、缓存主题状态这个我建议一定做。为什么否则每次重新打开 App。主题都会恢复默认。我的方案使用shared_preferences保存await prefs.setString( theme, dark, );启动时恢复。目前在 OpenHarmony 上没发现问题。十一、实际效果优化前问题表现深色模式适配不完整页面闪白存在状态栏颜色异常图标显示混乱优化后项目效果主题切换更稳定页面体验更统一暗黑适配基本完整页面切换更自然目前这套方案已经在项目里稳定用了挺长时间。十二、总结这次做 Flutter Dark Mode 在 OpenHarmony 下的适配一个比较明显的感受是深色模式真正麻烦的地方其实不是 ThemeMode。而是全局颜色管理页面细节统一图标资源状态栏页面生命周期尤其项目越来越大之后如果前期没有统一主题规范。后面补 Dark Mode 会非常痛苦。我现在项目里的原则基本是不直接写死颜色所有颜色统一 Theme 管理图标区分明暗资源页面背景统一配置状态栏跟随主题变化整体体验会稳定很多。后面我还准备继续研究Material 3 动态主题OpenHarmony 系统主题同步Flutter 动态换肤多主题架构设计希望这篇文章能给正在做 Flutter for OpenHarmony 开发的同学一点参考。