山海万灵 HarmonyOS 文化知识实战(09):深浅色资源与文化插画层级
文化知识应用的插画通常承担路线、地域、神兽与进度提示等信息。只替换页面背景色会让深色界面的山水纹理、金色强调色和卡片文本彼此争夺注意力;反过来,浅色界面也容易因透明图层过多而丢失边界。山海万灵把颜色、插画和组件表面拆成同一套主题分支,让主题切换直接驱动页面外壳、内容卡片与背景资源更新。

上图的浅色首页保留了山水路线、地域节点、统计卡和底部导航。卡片使用浅色表面和偏深文字,路线与“继续探索”按钮使用独立的强调色,避免在大面积插画上把所有信息都压成同一层。
把主题值收敛成可组合的令牌
页面不直接散落判断式颜色。ShanhaiTheme 为背景、卡片、边框、主次文本、金色强调与地图路线提供成对值,组件只根据 isDarkMode 读取语义化令牌。这样新增页面时只选择它需要的角色,不必重新发明一组深浅色常量。
static readonly PAGE_BG: string = '#07171C';
static readonly DARK_CARD_SURFACE: string = '#03171D';
static readonly DARK_CARD_RAISED: string = '#0A252C';
static readonly DARK_CARD_SELECTED: string = '#16444A';
static readonly LINE: string = '#2F6268';
static readonly GOLD: string = '#D8A84E';
static readonly CREAM: string = '#F7EBD3';
static readonly SUB_TEXT: string = '#B7CACB';
static readonly LIGHT_PAGE_BG: string = '#F6F0E4';
static readonly LIGHT_PANEL_BG: string = '#FFF9ED';
static readonly LIGHT_PANEL_BG_ALT: string = '#EAF1E4';
static readonly LIGHT_TAG_BG: string = '#E2EAD9';
static readonly LIGHT_LINE: string = '#C8B98F';
static readonly LIGHT_GOLD: string = '#A56F20';
static readonly LIGHT_CREAM: string = '#26372E';
static readonly LIGHT_SUB_TEXT: string = '#5F6D64';
static pageBg(isDarkMode: boolean): string {
return isDarkMode ? ShanhaiTheme.PAGE_BG : ShanhaiTheme.LIGHT_PAGE_BG;
}
static panelBg(isDarkMode: boolean): string {
return isDarkMode ? ShanhaiTheme.PANEL_BG : ShanhaiTheme.LIGHT_PANEL_BG;
}
static textPrimary(isDarkMode: boolean): string {
return isDarkMode ? ShanhaiTheme.CREAM : ShanhaiTheme.LIGHT_CREAM;
}
这种分层解决了两个常见问题:一是把“深色”误当作所有区域都用纯黑;二是让正文、辅助说明和禁用态共用同一种灰色。山海万灵的深色页面背景、主卡片、抬升卡片和输入表面分别对应不同深度,浅色页面也为卡片、替代表面和标签保留独立值。
| 视觉角色 | 深色主题 | 浅色主题 | 使用位置 |
|---|---|---|---|
| 页面外壳 | 深青黑 | 米白 | 整页背景与空白区域 |
| 内容卡片 | 深色半透明表面 | 暖白表面 | 统计、路线与阅读信息 |
| 强调信息 | 金色与青绿色 | 褐金与青绿色 | 进度、路线、主操作 |
| 次级文字 | 低饱和浅青 | 灰绿色 | 说明、计数和辅助状态 |
主题状态从页面入口向下传递
主题状态由首页统一持有。用户点击页头的主题控制后,页面状态发生一次明确更新;首页内容、图鉴、探索、馆长和“我的”模块接收相同的 isDarkMode,避免局部组件自行缓存旧主题。
ShanhaiHomePageContent({
beasts: this.beasts,
discoveredCount: this.discoveredIds.length,
passportCount: this.passportRegionIds.length,
isDarkMode: this.isDarkMode,
onToggleTheme: () => {
this.isDarkMode = !this.isDarkMode;
}
})
显式传递比在每个子组件中再次读取全局状态更容易检查。组件的颜色、边框和资源选择都依赖同一布尔值,切换时不会出现标题已变色而背景仍停留在旧图的分裂状态。对有选中态的地域卡和护照印章墙,主题与业务选中状态保持独立:切换外观不会重置发现记录、当前路线或阅读上下文。
页头的图标和点击区域同样接收主题状态。太阳与月亮资源随状态切换,透明圆形表面使用不同透明度;点击事件只通知页面入口更新状态,组件本身不保存第二份主题副本。
private themeToggleIcon(): Resource {
return this.isDarkMode
? $r('app.media.shanhai_toggle_moon_v2')
: $r('app.media.shanhai_toggle_sun_v2');
}
Stack() {
Image(this.themeToggleIcon())
.width(46)
.height(46)
.objectFit(ImageFit.Contain)
}
.width(54)
.height(54)
.backgroundColor(this.isDarkMode ? '#0CF7EBD3' : '#44FFFFFF')
.borderRadius(27)
.onClick(() => {
this.onToggleTheme();
})
插画资源也要成对选择
文化插画不是普通装饰。首页和展厅使用带有山水、云气和神兽的背景,它们的明暗关系决定了文本能否被读到。组件根据主题和宽度选择对应资源,再让主题令牌负责文字与卡片层级。
private panelAsset(): Resource {
return this.isDarkMode
? $r('app.media.shanhai_content_panel_dark_v4')
: $r('app.media.shanhai_content_panel_light_v4');
}
.backgroundImage(shanhaiPageBackdropAsset(
this.isDarkMode,
this.isWideScreen
))
这里有两个边界。第一,深色资源不是在浅色图片上简单加黑蒙层;月色、云纹和远山需要保留可辨识的亮度范围。第二,业务内容不能烘焙在插画里。统计数、地域名称、路线进度和按钮仍由 ArkUI 文本与组件绘制,因此主题切换、数据刷新和多设备布局不会破坏可访问性。

深色主题下,背景改为夜色山水和月纹,统计卡、金色数字、路线节点与底部导航仍可分辨。切换前后内容数据、地域路线和统计值保持不变,变化只发生在主题令牌与对应的插画资源分支。
容易被忽略的层级问题
深色模式的回归不只检查“有没有换色”。下面三类问题最容易在文化插画页面出现:
| 问题 | 表现 | 处理方式 |
|---|---|---|
| 文本被纹理吞没 | 地域名、说明和统计标签难以阅读 | 主次文本分别取主题令牌,卡片与插画之间保留不透明或半透明表面 |
| 选中态不明显 | 地图节点和底部导航无法区分当前项 | 选中背景、边框和金色强调同时参与状态表达,不只改变文字颜色 |
| 图片与布局脱节 | 宽屏下背景裁切后遮住内容 | 背景资源选择同时接收主题和宽度,内容区域仍按自适应间距布局 |
资源缺失时,页面应先保留主题颜色、标题、统计和导航等可操作信息,再使用安全的普通表面作为背景;不把一张加载失败的插画当成全页不可用。网络同步失败也不应改变用户已经选定的主题,页面可以提示数据来源状态,同时继续用本地内容完成阅读和探索。
验收:一次切换要同时检查哪些区域
验证时,从首页启动后依次观察页头、统计卡、路线图、主操作和底部导航;点击主题控制切换一次,再确认以下结果:
- 页面背景、山水插画和月亮/日间视觉随主题同时变化。
- 标题、说明、金色统计值、地域标签和路线节点仍保持足够对比度。
- 已发现数量、护照印章、知识节点和当前路线不因切换而改变。
- 底部导航的当前项与未选中项仍有可区分的颜色和表面层级。
- 返回其他一级页面后,卡片、边框和插画继续使用同一主题状态。
统一的主题令牌把颜色选择收拢在可维护的入口,成对插画资源解决文化画面在不同亮度下的阅读问题,显式状态传递则保证首页与各功能模块在一次主题切换后保持同步。更多 ArkUI 状态管理方式可参考 HarmonyOS 官方状态管理文档。
更多推荐

所有评论(0)