ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

HarmonyOS 应用开发之HarmonyOS 深色模式适配:dark 限定词资源与 isDark 状态管理详解

HarmonyOS 应用开发之HarmonyOS 深色模式适配:dark 限定词资源与 isDark 状态管理详解 HarmonyOS 深色模式适配dark 限定词资源与 isDark 状态管理一、引言深色模式早已不是锦上添花的视觉选项而是短视频、视频播放这类高频使用的应用的必备能力夜间刷视频时刺眼的白色页面会显著加速视觉疲劳而在沉浸式全屏播放场景下深色界面更是保证画面观感一致的前提。multi-short-video 工程覆盖直板机、折叠屏、平板、PC、电视与手表六类设备深浅色适配既要做到资源零成本切换又要处理页签切换带动主题变化这类业务态联动还要为 PC 端的窗口装饰标题栏按钮单独设置深色样式。HarmonyOS 的深色模式适配遵循一条核心理念差异化是声明出来的不是判断出来的。颜色、图片等资源通过dark限定词目录在编译期声明两套取值系统在运行期自动匹配业务代码中真正需要判断的只有跟随业务状态变化的主题切换逻辑如本工程首页推荐页浅色、个人页深色的产品诉求。本文以工程内真实代码为例拆解 dark 限定词资源、color.json 管理、isDark 状态同步与深色图标四部分。二、dark 限定词目录与 color.json 深浅色资源管理限定词Qualifier是资源自适应的核心机制目录名中dark表示设备处于深色模式时命中此目录base则是任何条件下的兜底目录。系统按最匹配优先规则选择资源命不中任何限定词时回退base。本工程在features/multishortvideocomment与features/multishortvideoindividual两个模块中同时维护了base与dark两份颜色资源代码统一用$r(app.color.xxx)引用深浅色切换在运行期自动完成。以评论模块为例浅色与深色下的颜色取值对比资源名base浅色dark深色用途text_input_bg_xs#F2F2F2#37393A小屏评论输入框背景text_input_bg_md#2C2E2D#2C2E2D大屏输入框背景恒深色text_input_row_bg_xs#FFFFFF#66000000评论输入行背景send_bg_xs#FFFFFF#FF8B9194小屏发送按钮背景font_emphasize_light#0A59F7#0A59F7强调色浅色变体font_emphasize_dark#317AF7#317AF7强调色深色变体对应的两份资源文件内容节选// d:\HarmonyOS\WorkSpace\multi-short-video\features\multishortvideocomment\src\main\resources\base\element\color.json { color: [ { name: text_input_bg_xs, value: #F2F2F2 }, { name: text_input_row_bg_xs, value: #FFFFFF }, { name: send_bg_xs, value: #FFFFFF } ] }// d:\HarmonyOS\WorkSpace\multi-short-video\features\multishortvideocomment\src\main\resources\dark\element\color.json { color: [ { name: text_input_bg_xs, value: #37393A }, { name: text_input_row_bg_xs, value: #66000000 }, { name: send_bg_xs, value: #FF8B9194 } ] }注意一个细节dark目录只需覆盖需要变化的资源未列出的资源自动回退base取值因此text_input_bg_md在两份文件中值相同都是深色输入框属正常复用。个人作品页模块同样遵循该模式introduction_bg_xs从浅色的#FFFFFF变为深色的#000000tags_bg_xs从#F5F5F5变为#37393A说明同一套机制可以低成本复制到每个模块。三、isDark 状态同步与主题切换资源层解决了系统深浅色的自动适配但本工程还有一个业务层面的诉求首页页签下推荐页呈现浅色我的个人页呈现深色且折叠屏等大屏设备上要求我的页恒为深色。这个状态与系统主题无关必须在代码层维护并下发到所有需要感知的组件。工程的做法是入口页用Provider(isDark)提供状态页签切换时按业务规则更新公共组件与子页面用Consumer(isDark)接收。// d:\HarmonyOS\WorkSpace\multi-short-video\products\default\src\main\ets\view\Index.ets Entry ComponentV2 struct Index { Provider(isDark) isDark: boolean false; // ... build() { Navigation(this.pathStack) { MSVTabs({ data: this.data, isDark: this.isDark, onIndexChange: (index: number) { if (index 0 this.subTabIndex 4) { this.isDark false; // 推荐页浅色 } else if (index 4) { // 我的页小屏深色大屏按断点决定 this.isDark new WidthBreakpointTypeboolean(true, true, false, false) .getValue(this.windowInfo.widthBp) } else { this.isDark true; // 其余页签深色 } } }) } } }isDark通过 Provider/Consumer 树向整个页面子树广播MSVTabs的 TabBar 用this.isDark ? params.iconDark : params.icon选择图标、用this.isDark ? this.selectedDarkColor : this.selectedLightColor选择文字颜色见common/multishortvideobase/src/main/ets/components/MSVTabs.ets个人页组件Individual.ets内声明Consumer(isDark)消费同一份状态用于选择ic_modify/ic_modify_dark等图标。这套 V2 装饰器方案相比逐层传参解耦了状态来源与状态消费方新增一个需要感知主题的组件只需声明一个Consumer即可。四、图片与图标的深色资源管理深色模式下纯黑色图标会融入深色背景导致看不见因此图标需要成对提供。本工程有三种组织方式按复用范围从小到大排列。第一种是后缀命名 代码判断如评论模块的点赞心形图标浅色版ic_heart.svg填充色为黑色半透明fill-opacity0.6深色版ic_heart_light.svg填充色为白色半透明!-- features/multishortvideocomment/src/main/resources/base/media/ic_heart.svg节选 -- path id矢量 1 dM1.68001 6.22669C... fillrgb(0,0,0) fill-opacity0.600000024 /!-- features/multishortvideocomment/src/main/resources/base/media/ic_heart_light.svg节选 -- path id矢量 1 dM1.68001 6.22669C... fillrgb(255,255,255) fill-opacity0.600000024 /评论页用WidthBreakpointTypeResource结合断点选择小屏用ic_heart大屏PC/平板通常配深色背景用ic_heart_lightComment.ets第 86~91 行MSVTextIcon({ src: new WidthBreakpointTypeResource($r(app.media.ic_heart), $r(app.media.ic_heart), $r(app.media.ic_heart_light), $r(app.media.ic_heart_light)).getValue(this.windowInfo.widthBp), iconSize: deviceInfo.deviceType tv ? 28 : 16 })第二种是MSVDataModel 的iconDark字段首页 TabBar 的号图标通过数据模型同时携带深浅两版资源products/default/.../viewmodel/MainTabsViewModel.etsthis.mainTabsData.push(new MSVDataModel(add, , true, $r(app.media.ic_plus), $r(app.media.ic_plus_dark)));MSVTabs渲染时按isDark直接二选一与第一种方式相比把成对资源收进数据模型UI 层不再需要条件表达式。第三种是纯限定词目录方案不区分后缀、将图片放进dark目录靠系统自动切换。工程中 PC 模块的ic_person.svg/ic_person_dark.svg、ic_ellipsis_message_badge_circle.svg/ic_ellipsis_message_badge_circle_dark.svg目前采用后缀方案。当主题变体增多时迁移到dark/media目录是更彻底的演进方向——代码引用不变差异化完全由资源系统承担。五、深色下视频页表现与 PC 端窗口装饰视频页面天然是深色优先全屏沉浸式播放时播放器区域为视频画面本身四周控件浮层采用半透明深色底与系统深色模式天然兼容。工程中AdaptiveVideo的交互浮层点赞、评论、分享等按钮叠加在视频之上控件本身使用白色系图标深浅色感知主要由外层页面承担这正是短视频应用常见的设计取舍——视频场景深色是常态浅色适配反而要克制。PC 端还多一层窗口装饰的深色问题窗口标题栏的最小化/最大化/关闭按钮样式不随页面主题变化需要显式设置。products/pc/.../pcability/MultiShortVideoPcAbility.ets中import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from kit.AbilityKit; windowStage?.getMainWindowSync().setDecorButtonStyle({ colorMode: ConfigurationConstant.ColorMode.COLOR_MODE_DARK });这行代码把 PC 窗口装饰按钮固定为深色样式与工程PC 端内容区默认深色的产品定位保持一致。类似地状态栏文字颜色通过setWindowSystemBarProperties({ statusBarContentColor: #FFFFFF })设置保证深色内容区上的状态栏文字可读。多设备视角下深色策略还应随形态收敛。手表端products/wearable/.../view/Index.ets同样声明Provider(isDark) isDark: boolean false由SubTabsComponent消费——小屏设备上深色判断简单内容区深色、控件浮层透明无需复杂的断点逻辑TV 端则更特殊大屏沉浸式观看场景下除了页面深色还要保证遥控器焦点框与内容的对比度工程让 TV 的页签与内容区保持深色基调避免焦点框与浅色内容混叠。因此在推进深色适配时各产品模块的isDark初始值与切换规则可以独立演进公共组件MSVTabs只负责按isDark渲染、不感知具体业务规则——这再次体现了公共层管能力、产品层管策略的分层思想。六、深浅色切换的验证与常见问题深色模式上线前需要一套可执行的验证清单避免代码写得对、实际切不过来的尴尬。第一类是系统主题切换验证在真机/模拟器的系统设置中切换浅色与深色逐个页面检查颜色资源是否跟随变化——重点检查依赖dark/element/color.json的模块评论输入框、个人页标签背景确认未列出的资源正确回退base。第二类是业务态主题验证在首页推荐/关注/我的页签间来回切换确认Provider(isDark)按预期更新MSVTabs的文字色、图标与下划线同步变化且折叠屏展开/折叠断点变化时我的页的深色策略WidthBreakpointTypeboolean(true, true, false, false)正确命中。工程实践中容易踩的三类典型问题值得提前防范资源名冲突被静默覆盖不同模块定义了同名颜色如都叫text_input_bg_xs模块内引用各自命中本模块资源、表面正常但跨模块复用时容易拿错取值。规避手段是保持资源名语义化并在评审时核对资源归属模块对应第 55 篇文章的资源命名纪律。深色图标与背景错配图标成对资源靠_dark/_light后缀约定但系统深色模式与业务深色页面是两套判断ic_heart_light的选用跟随断点而非系统主题若产品后续要求手机端我的页也走深色需同步调整WidthBreakpointType的取值分支否则会出现浅色图标压在深色背景上不可见的问题。系统栏与页面主题脱节状态栏文字颜色用statusBarContentColor: #FFFFFF写死为白色在浅色页面会与浅色背景融为一体。更稳妥的做法是跟随页面主题动态设置或在深色页面统一白字、浅色页面统一黑字并纳入验证清单逐页检查。把验证清单固化为深浅色遍历用例配合第 54 篇文章的 UI 测试每次发版前跑一遍深色相关问题基本可以归零。七、总结与最佳实践深色模式适配在本工程中沉淀为四条可复制的最佳实践颜色一律走$r(app.color.xxx)与限定词深浅色取值声明在base/dark两份color.json中业务代码不做任何条件判断系统自动匹配dark目录只覆盖需要变化的资源其余自动回退。业务态主题用 Provider/Consumer 管理当哪个页面是深色由业务逻辑决定而非系统主题时用Provider(isDark)广播、Consumer(isDark)消费避免逐层透传断点参与决策时组合WidthBreakpointType。图标成对管理、命名可识别深色变体统一_dark/_light后缀ic_heart_light.svg、ic_plus_dark.png或用MSVDataModel.iconDark字段把成对资源收进模型变体增多后迁移到dark/media目录实现零判断切换。平台专属深色单独处理PC 窗口装饰按钮用setDecorButtonStyle({ colorMode: COLOR_MODE_DARK })系统栏文字用statusBarContentColor配置这类窗口层深色不走资源限定词需要在 Ability 生命周期内显式设置。遵循这四条新模块接入深色模式时只需补齐dark/element/color.json与成对图标即可与既有页面保持一致体验。
返回列表