Flutter Dark Mode 在 OpenHarmony 系统中的适配实践
本文分享了在OpenHarmony系统中适配Flutter深色模式的实践经验。作者最初低估了适配难度,实际遇到页面不更新、组件颜色异常、状态栏不一致等问题。解决方案包括:拆分明暗主题、避免硬编码颜色、监听系统亮度变化、适配状态栏和图片资源、使用Provider管理主题状态等。文章强调全局颜色管理和统一规范的重要性,建议所有颜色通过Theme管理,图标区分明暗资源,页面背景统一配置。最终实现了稳定的
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
Flutter Dark Mode 在 OpenHarmony 系统中的适配实践
前言
最近在做 Flutter for OpenHarmony 项目时,深色模式适配这块花的时间比我预想中要多。
一开始我以为:
Flutter 本身已经支持 ThemeMode 了,适配暗黑模式应该不复杂。
结果真正接入 OpenHarmony 真机之后,还是遇到了一堆细节问题。
包括:
- 系统深色模式切换后页面不更新
- 部分组件颜色异常
- 状态栏颜色不统一
- 页面切换时闪白
- 图片资源不适配暗色主题
尤其是多个页面叠加后,颜色管理会越来越乱。
后面我重新整理了一套主题管理方案,整体体验才稳定下来。
这篇文章主要记录一下我这次在 OpenHarmony 项目里的 Dark Mode 适配过程。
一、为什么现在必须适配 Dark Mode
现在大部分系统都已经默认支持深色模式。
包括:
- Android
- iOS
- OpenHarmony
如果应用完全不适配:
用户体验会比较割裂。
尤其晚上使用时:
亮白页面会特别突兀。
我项目里的实际场景
当前项目包括:
- 首页
- 商品列表
- IM 聊天
- 用户中心
- WebView 页面
很多页面一开始都是直接写死颜色:
Container(
color: Colors.white,
)
结果系统切暗黑模式后:
页面直接“半黑半白”。
二、Flutter ThemeMode 基础接入
Flutter 本身已经提供了主题切换方案。
MaterialApp 配置
MaterialApp(
theme: lightTheme,
darkTheme: darkTheme,
themeMode: ThemeMode.system,
)
这里:
ThemeMode.system
表示:
跟随系统主题。
三、浅色主题与深色主题拆分
后面我把所有主题单独拆了。
light_theme.dart
final ThemeData lightTheme = ThemeData(
brightness: Brightness.light,
scaffoldBackgroundColor: Colors.white,
appBarTheme: const AppBarTheme(
backgroundColor: Colors.white,
),
);
dark_theme.dart
final 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。
ThemeProvider
class ThemeProvider
extends ChangeNotifier {
ThemeMode themeMode =
ThemeMode.system;
void changeTheme(
ThemeMode mode) {
themeMode = mode;
notifyListeners();
}
}
页面切换:
context
.read<ThemeProvider>()
.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 开发的同学一点参考。
更多推荐

所有评论(0)