鸿蒙这套课程学到 ArkUI 进阶这一块,沉浸式和深色模式是两个特别像“细节”但实际非常影响体验的能力。沉浸式说白了就是让页面内容延伸到状态栏、导航栏下面,把整块屏幕真正利用起来;深色模式则是让你的应用跟随系统在深色环境下自动变换配色、图片和文字风格。这篇文章是这节课的完整笔记整理,重点集中在两件事:一是如何用 API 12 之后的新写法把页面做成沉浸式,二是如何通过资源限定词扎实地适配深色模式。这些都不是“能跑就行”的逻辑,更多是“跟系统原生体验融为一体”的问题。
如果你已经掌握了 ArkUI 的基础布局、生命周期和组件化思想,但开始做完整页面时会觉得顶部状态栏突兀、深色模式切换后页面配色一团糟,那这份笔记就是给你准备的。里面除了原理和代码,我也把实践中踩过的一些坑一并写了出来,方便你对照排查。
1. 为什么“沉浸式+深色模式”是鸿蒙应用避不开的两道坎
1.1 沉浸式不是“把背景图拉满”那么简单
很多新人会把沉浸式理解成“把页面背景色铺满整个屏幕”,这种做法确实能让状态栏区域不再是刺眼的白色或者黑色,但真正做起来会发现,这只是最浅的一层。沉浸式的本质是让应用内容和系统 UI 边界融为一体。顶部状态栏、底部导航栏和页面内容之间,不再有那种明显的“割裂感”。
举个例子,一个阅读类的资讯页,如果顶部是一张 960 像素宽的大图,状态栏还是默认的白底黑字,画面就会从大图中间硬生生切出一条白条,整个高级感瞬间没了。用户并不会说“这个状态栏没沉浸”,但会觉得这个 App 做得“不够精致”。尤其是现在用户看惯了各种头部 App 的界面,对这种细节其实非常敏感。
在鸿蒙里做沉浸式,不是单纯改一个背景色就完事。你需要处理窗口的行为、状态栏文字和图标的颜色、安全区的避让,以及内容真正延伸到状态栏之后的布局问题。这套流程在 API 12 之前和之后有明显的差异,后面专门用一节来讲。
1.2 深色模式是被用户逼出来的功能
深色模式早就不只是“夜间模式”了。用户选择深色模式的原因五花八门:有人为了晚上刷手机不刺眼,有人觉得 OLED 屏幕下深色界面更省电,也有人单纯就是喜欢深色界面的质感。系统级的深色模式开关一旦打开,如果你的应用不做适配,页面就会保持一片刺眼的白色,这几乎是所有应用中最容易招骂的体验问题之一。
更麻烦的一点是,深色模式不是“做个黑色的背景”就可以的。文字颜色、分割线颜色、阴影深浅、图标形态、图片氛围、甚至毛玻璃效果都要跟着变。一个纯黑背景配上灰色文字可能看不清,一个深色背景上再放一个亮色阴影会显得特别奇怪。这些都是适配时要考虑的内容。
鸿蒙的深色模式适配机制非常依赖资源限定词。如果一开始设计资源文件时就没有把逻辑整理清楚,等页面多起来之后再返工,工作量会成倍增长。所以,在项目早期建立一套规范的资源目录体系,比后续打补丁要省心得多。
1.3 谁最需要读这部分笔记
这套笔记适合两类人。第一类是正在做鸿蒙应用的中级开发者,已经能独立写出页面了,但开始关注体验细节,需要把沉浸式和深色模式做成“系统级”的效果。第二类是准备鸿蒙开发面试的候选人,因为这两块内容是面试中被问得比较多的功能点,尤其是“你如何做沉浸式状态栏”“深色模式怎么适配”这种问题,几乎属于高频题。如果你只是刚学会摆布局、写事件,建议先把基础再过一遍,再来啃这部分内容。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 沉浸式状态栏的前置知识与 API 选型
2.1 状态栏、导航栏、安全区,先把这三个概念掰扯清楚
要在代码里做沉浸式,得先把几个名词对齐。顶部状态栏就是显示时间、信号、电量的区域,底部导航栏在鸿蒙手机上通常是那条细小的手势条,也可能是一排虚拟按键。两者都属于系统 UI,应用默认情况下内容区域是不会画到它们下面去的。
安全区这个概念和 iOS 里的 SafeArea 很像。它指的是系统 UI 没有遮挡的那部分区域。顶部状态栏会占据一个安全区,底部导航栏也会占据一个安全区,某些带有打孔摄像头的设备,摄像头区域也会有额外的安全区要求。正常布局时,内容自动限制在安全区内部;做沉浸式时,你希望某些内容突破安全区,延伸到状态栏后面。
理解这三个概念的关键是分清“系统 UI 显示的区域”和“应用内容可绘制的区域”。沉浸式做的是让应用内容可绘制区域扩大到整个屏幕,而布局时再针对安全区做合适的避让或延伸。两者并不是一回事。
2.2 旧方案:窗口级全屏方式
早期做沉浸式,核心用法是通过 Window 对象把窗口设置为全屏布局。窗口级的意思是:这个设置影响的是整个应用窗口,不区分页面。基础步骤如下:
第一,在入口 UIAbility 的 onWindowStageCreate 里拿到 WindowStage,然后获取主窗口实例。第二,调用 setWindowLayoutFullScreen(true) 让内容延伸到状态栏和导航栏下面。第三,通过 setWindowSystemBarProperties 设置状态栏的背景色和内容颜色,保证状态栏区域跟页面融为一体。
ts复制import { window } from '@kit.ArkUI';
onWindowStageCreate(windowStage: window.WindowStage): void {
const win = windowStage.getMainWindowSync();
win.setWindowLayoutFullScreen(true);
win.setWindowSystemBarProperties({
statusBarColor: '#00000000',
statusBarContentColor: '#FFFFFF',
navigationBarColor: '#00000000',
navigationBarContentColor: '#FFFFFF'
});
}
这段代码是典型的老式沉浸式做法。statusBarColor 设为全透明,让页面内容能透过状态栏显示;statusBarContentColor 用来设置状态栏上的文字和图标颜色。
这个方案最大的问题是“全局生效”。页面 A 的背景是深色图,状态栏文字需要白色;页面 B 的背景是浅色,状态栏文字又需要黑色。同一个窗口配置不可能同时满足两个页面,所以往往还得在页面 aboutToAppear 里再通过 window.getLastWindow(getContext(this)) 去动态调整属性。做起来繁琐,容易漏改。
2.3 新方案:组件级 expandSafeArea
API 12 之后,ArkUI 提供了组件级的 expandSafeArea 属性。这个属性可以直接挂在某个组件上,让该组件单独扩展到安全区外,而不必把整个窗口都变成全屏。这个设计思路其实更贴近实际业务——很多时候你只想让顶部的图片延伸上去,而不是让整个页面的所有内容都顶到状态栏后面。
基本用法是在目标组件后面链式调用:
ts复制Column() {
// 顶部大图区
Image($r('app.media.banner'))
.width('100%')
.height(300)
}
.expandSafeArea(
[SafeAreaType.SYSTEM],
[SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]
)
SafeAreaType.SYSTEM 代表系统安全区,也就是状态栏、导航栏这些系统 UI 占据的区域。SafeAreaEdge.TOP 和 SafeAreaEdge.BOTTOM 则代表向顶部和底部扩展。组件一旦声明扩展,它会绘制到安全区内部,但同时布局系统会自动处理原来安全区的占位,避免出现内容被状态栏文字遮挡的情况。
这个方案相比窗口级全屏,最大的好处是局部化。哪个组件需要沉浸,就单独加属性,不会影响整页布局。而且默认情况下,系统会自动调整布局避让逻辑,你不需要手动给状态栏高度加 padding。
2.4 两个方案怎么选
从我实际工作中的使用体验来看,这两个方案并不是互斥的,更多是配合使用。如果你要做的是全屏背景类的页面,比如闪屏页、内容详情页,采用窗口级全屏配置配合透明状态栏,效果最直接。但如果你只是希望某个局部区域延伸上去,比如资讯页顶部大图、个人主页的头部背景,用 expandSafeArea 更合适。
另外要提醒一点:即使你用 expandSafeArea,状态栏文字的颜色依然需要单独管理。因为内容延伸上去了,状态栏区域的背景可能是深色也可能浅色,如果状态栏文字颜色没有跟着变,就会出现内容顶上去但字看不清的尴尬情况。这部分需要在页面里根据背景动态切换状态栏文字颜色。
3. 深色模式适配:资源限定词是核心
3.1 认识限定词目录:dark 到底放在哪
鸿蒙深色模式的核心机制是资源限定词。你可以简单地把它理解为:同一份代码,系统会根据当前主题去不同的资源目录下寻找资源文件。默认资源放在 resources/base 目录下,深色主题的资源放在 resources/dark 目录下。
text复制resources/
├── base/
│ ├── element/
│ │ ├── color.json
│ │ ├── string.json
│ │ └── float.json
│ └── media/
│ └── banner.png
└── dark/
├── element/
│ ├── color.json
│ ├── string.json
│ └── float.json
└── media/
└── banner.png
当代码里写 $r('app.color.bg_color') 时,系统在浅色模式下读取 resources/base/element/color.json 里的对应颜色,在深色模式下读取 resources/dark/element/color.json 里的对应颜色。文件名一定要完全一致,目录结构也要保持一致,否则系统找不到对应的深色资源,就只能回退到默认资源。
这里有个容易踩的坑:很多人会认为深色模式只需要把背景色换深就可以了,于是只在 dark/element/color.json 里定义了背景色。结果深色模式一切换,页面背景确实变深了,但文字颜色和分割线颜色还是原来的,整体效果非常突兀。适配深色模式,应该把页面上所有用到的语义化颜色都在 dark 目录下重新定义一遍,而不是只改背景。
3.2 适配颜色、图片、阴影、毛玻璃
颜色适配是最基础的一环。建议你在项目早期就建立一套语义化的颜色命名,比如 text_color_primary、text_color_secondary、bg_color_page、divider_color,而不是直接用 text_black、bg_white 这种描述具体颜色的命名。语义化命名的好处是,在深色模式下你只需要重新定义这套语义对应的色值,不需要回代码里找每个引用点。
拿一个新闻类页面举例,浅色模式下背景色是 #F1F3F5,文字主色是 #182431;深色模式下背景色应该变成 #0A0A0A 或类似接近纯黑的颜色,文字主色则变成 #E6E6E6 这类高亮度的浅色。如果直接写了一堆硬编码色值在代码里,深色模式适配时就只能逐个找、逐个改,非常痛苦。
图片适配比颜色更讲究。如果你的图片本身带大面积的白底或者亮色,放到深色背景下会非常刺眼。最简单的办法是准备两张同名图片,分别放在 base/media 和 dark/media 下,系统会自动切换。比如 banner 图在浅色模式下是明亮色调,深色模式下可以换成同内容但整体压暗的版本。
阴影在深色模式下的处理也容易被忽视。深色背景下再使用默认的阴影,会显得脏兮兮的。一般做法是深色模式下减少阴影的模糊半径和透明度,或者干脆去掉阴影,用细线条边框来替代层次感。
毛玻璃效果在深色模式下比较特殊。浅色模式下的毛玻璃通常是半透明白加模糊,但深色模式下的毛玻璃如果透明度控制不好,会出现“脏玻璃”的感觉。建议深色模式下把毛玻璃的背景色饱和度降下来,透明度调低一点,整体更干净。
3.3 获取当前模式与监听系统切换
资源会自动切换,但某些业务逻辑还是需要知道当前是不是深色模式。比如地图组件可能需要根据颜色模式换地图样式,图表组件需要重新设置坐标轴颜色。这种场景下,你需要主动获取当前颜色模式。
以在页面中获取为例:
ts复制import { common, ConfigurationConstant } from '@kit.AbilityKit';
const context = getContext(this) as common.UIAbilityContext;
const config = context.getConfigurationSync();
if (config.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
// 当前为深色模式
}
如果你需要在系统切换深浅色时感知变化,可以在 UIAbility 里重写 onConfigurationUpdated 方法:
ts复制import { UIAbility, Configuration } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
onConfigurationUpdated(newConfig: Configuration): void {
if (newConfig.colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
// 通知页面或全局状态管理器更新
}
}
}
需要注意一点:应用在后台时如果用户切换了系统深浅色,onConfigurationUpdated 不一定会立刻回调到所有页面。回到前台以后,建议在 onPageShow 里重新获取一次当前颜色模式,避免出现界面状态和系统不一致的情况。
4. 应用内手动切换与全局状态管理
4.1 应用级手动切换模式
很多 App 并不会直接跟随系统,而是提供应用内的“跟随系统 / 浅色 / 深色”三档设置。鸿蒙里可以设置应用级的颜色模式,让它覆盖或跟随系统配置。
ts复制import { common, ConfigurationConstant } from '@kit.AbilityKit';
const context = getContext(this) as common.UIAbilityContext;
const appContext = context.getApplicationContext();
appContext.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK);
调用 setColorMode 之后,应用所有页面的资源引用都会立刻重新求值,也就是 $r 引用的颜色、图片、字符串等都会自动切换到对应模式。这一点非常方便,省去了到处刷新页面状态的操作。
但这里有一个容易误解的地方:应用内切换颜色模式只会影响你自己的应用,不会改动系统级别或别的应用的显示。它相当于应用内部覆盖了系统主题设置。
4.2 页面刷新与状态同步
虽然 $r 资源会自动切换,但如果你在代码里直接给组件设置了颜色值,比如:
ts复制Text('标题')
.fontColor('#182431')
这段代码不会因为颜色模式切换而变化。只有通过 $r('app.color.xxx') 引用资源,才能实现自动切换。
为了让手动切换模式后动态绑定的数据也能同步刷新,我一般会引入一个全局主题状态。比如在入口组件里初始化:
ts复制AppStorage.setOrCreate('currentColorMode', ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
然后在页面里通过 @StorageProp 来观察:
ts复制@StorageProp('currentColorMode') currentColorMode: number = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
切换模式时更新全局状态:
ts复制AppStorage.setOrCreate('currentColorMode', ConfigurationConstant.ColorMode.COLOR_MODE_DARK);
页面里使用 @StorageProp 修饰的变量,状态一变就会自动渲染。这样即便有动态计算的样式,也能跟着切换。
4.3 持久化与启动恢复
如果应用支持用户手动选择模式,那这个选择一定要做持久化。否则用户切回浅色模式,重启应用后又回到跟随系统,体验很割裂。
常规做法是用 Preferences 把用户选择保存下来。在应用启动时读取,如果用户上次选择过深色或浅色,就调用 setColorMode 设置,再加载后续页面;如果没有选择过,就让应用跟随系统。
这里有一个细节:启动阶段设置模式的时机很重要。最好在 UIAbility 的 onCreate 或 onWindowStageCreate 之前完成设置,否则启动画面或者首页可能先用默认模式渲染一帧,再切换成目标模式,产生闪烁感。实测下来,把读取和设置逻辑放到 onWindowStageCreate 的前面,能明显减少这种闪烁。
5. 实操:搭建一个带沉浸式大图+深色模式的资讯页
5.1 页面设计与目录结构
为了把前面提到的沉浸式和深色模式串起来,我做一个最简单的资讯详情页。页面结构从上到下是:顶部大图、标题、正文。顶部大图延伸到状态栏后面,状态栏文字颜色跟大图颜色匹配。页面整体使用语义化颜色,深色模式下自动切换。
目录结构如下:
text复制entry/src/main/resources/
├── base/
│ ├── element/
│ │ ├── color.json
│ │ └── string.json
│ └── media/
│ ├── banner.png
│ └── icon_placeholder.png
└── dark/
├── element/
│ ├── color.json
│ └── string.json
└── media/
├── banner.png
└── icon_placeholder.png
5.2 沉浸式代码逐行拆解
页面使用 expandSafeArea 让顶部大图延伸到状态栏。由于页面整体默认没有被设置为全屏窗口,只在需要的地方扩展,这样可以避免整页内容都跑到状态栏下面。
ts复制import { SafeAreaType, SafeAreaEdge } from '@kit.ArkUI';
@Entry
@Component
struct ArticleDetailPage {
@State title: string = '鸿蒙沉浸式与深色模式实践';
build() {
Scroll() {
Column() {
Stack() {
Image($r('app.media.banner'))
.width('100%')
.height(320)
.objectFit(ImageFit.Cover)
Column() {
Text(this.title)
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.text_color_inverse'))
}
.width('100%')
.padding({ left: 20, right: 20, bottom: 20 })
.alignItems(HorizontalAlign.Start)
.position({ y: 240 })
}
.width('100%')
.height(320)
Column() {
Text('正文区域')
.fontSize(17)
.fontColor($r('app.color.text_color_primary'))
.lineHeight(28)
.margin({ top: 16 })
}
.width('100%')
.padding(20)
}
}
.expandSafeArea(
[SafeAreaType.SYSTEM],
[SafeAreaEdge.TOP]
)
}
}
这段代码的核心点在最后那个 expandSafeArea。声明之后,大图区域会向顶部延伸到状态栏后面,但同时布局系统会自动给下面内容做安全区避让,所以正文不会顶着状态栏。这里我用了 Stack 让标题文字盖在大图底部,文字颜色用了反白色(text_color_inverse),保证在大多数深色图片上可读。
状态栏文字颜色在浅色模式下如果没有单独设置,默认是深色,这在浅色大图上问题不大。但如果大图本身是深色,就需要主动把状态栏内容颜色调成白色。通常可以在 aboutToAppear 里做一次设置:
ts复制aboutToAppear(): void {
window.getLastWindow(getContext(this)).then((win) => {
win.setWindowSystemBarProperties({
statusBarColor: '#00000000',
statusBarContentColor: '#FFFFFF'
});
});
}
需要注意的是,window.getLastWindow 是异步的,在页面初始化阶段调用时可能需要等待窗口创建完毕。实战中如果发现拿不到窗口,可以放到 onPageShow 里再做,这个时机一般窗口已经可用了。
5.3 深色资源文件怎么组织
颜色资源使用语义化命名。浅色模式下,resources/base/element/color.json 内容如下:
json复制{
"color": [
{
"name": "text_color_primary",
"value": "#182431"
},
{
"name": "text_color_inverse",
"value": "#FFFFFF"
},
{
"name": "bg_color_page",
"value": "#F1F3F5"
}
]
}
深色模式下,resources/dark/element/color.json 内容如下:
json复制{
"color": [
{
"name": "text_color_primary",
"value": "#E6E6E6"
},
{
"name": "text_color_inverse",
"value": "#FFFFFF"
},
{
"name": "bg_color_page",
"value": "#0A0A0A"
}
]
}
这里的 text_color_inverse 在两种模式下都保持了白色,因为在深色大图场景下,反白文字始终需要白色。而 text_color_primary 在浅色模式下是深色,深色模式下变成了浅色,页面正文的字体颜色就会自动跟着主题变化。
图片的做法类似。resources/base/media/banner.png 可以放一张明亮的配图,resources/dark/media/banner.png 放同样尺寸但整体暗色调的版本。通过 $r('app.media.banner') 引用时,系统会自动选择对应文件。
这里有一个容易踩的坑:深色目录下的媒体文件必须和基础目录保持同名。如果名字不同,系统不会自动切换,而是走默认资源。之前我在 dark/media 下放了 banner_dark.png,然后在代码里写死 $r('app.media.banner_dark'),结果深色模式下确实显示了暗图,但切回浅色模式就找不到图片了,因为浅色目录下没有这个文件。正确的做法是保持同名。
5.4 联调验证
在 DevEco Studio 里验证时,最简单的办法是用 Previewer。Previewer 右上角有一个主题切换入口,可以快速在浅色和深色之间切换。切完之后可以直接看到页面的资源切换效果,不需要每次都用真机。
真机调试时,系统的设置里切换深浅色模式,应用应该会实时变化。如果页面没有变化,先看是不是页面里用了硬编码颜色,再看 UIAbility 里是否实现了 onConfigurationUpdated。不过对于资源文件切换来说,系统配置更新后页面会自动重绘,一般不需要额外监听。
还要验证沉浸式的效果:检查顶部大图是否顶到了状态栏上面,状态栏文字颜色是否清晰可读。如果发现大图顶上去之后状态栏区域出现了黑条,多半是窗口的背景色没有设置为透明,或者 setWindowSystemBarProperties 里的 statusBarColor 没有设为透明色。
6. 常见问题与排查经验
6.1 高频问题速查表
| 问题 | 现象 | 原因 | 解决办法 |
|---|---|---|---|
| 状态栏背景不透明 | 状态栏区域出现黑条或白条 | 未调用 setWindowLayoutFullScreen(true) 或 statusBarColor 未设置透明 |
检查窗口配置,将 statusBarColor 设为 #00000000 |
| 状态栏文字看不清 | 深色背景配深色字,或者浅色背景配白色字 | 没有根据页面背景设置 statusBarContentColor |
在页面生命周期里动态调整状态栏文字颜色 |
| 深色模式只改背景色 | 背景变深,但文字、分割线仍保持浅色 | 只定义了 dark/element/color.json 里的背景色,未定义全部语义化颜色 |
把所有用到的颜色资源都定义一套深色值 |
| 深色模式图片没有切换 | 图片在深浅色模式下看起来一样 | 深色目录下的媒体文件与基础目录文件名不一致 | 保持两个目录下的同名文件 |
| 应用重启后丢失用户选择的主题模式 | 用户选择深色,重启后回到默认 | 没有持久化用户选择 | 用 Preferences 保存,并在启动时提前设置 |
| 页面切回前台后主题颜色不正常 | 系统切换深浅色后,回到应用页面颜色错乱 | onConfigurationUpdated 在后台时未触发,或页面未重新读取配置 |
在 onPageShow 或 onForeground 里重新检查颜色模式 |
6.2 状态栏文字颜色看不清的三种场景
第一种场景是深色背景配深色字。页面背景用了深蓝色大图,但状态栏文字还是默认的黑色,结果就是看不清。这种情况需要把 statusBarContentColor 设置为白色。
第二种场景正好反过来,浅色背景配白色字。这种通常出现在沉浸式页面往下滚动后,背景从深色图片变成了白色正文区域,但状态栏文字颜色还是白色,结果顶部一行字看不清。很多开发者只处理了页面加载时的状态,忘了处理滚动时的状态。解决方案是监听滚动位置,在内容从深色区域进入浅色区域时切换文字颜色。用 Scroll 或 List 的 onScrollIndex 可以拿到滚动位置,再据此刻切换。
第三种场景是深色模式切换到浅色模式的瞬间,状态栏文字颜色和背景颜色不匹配,出现短暂闪烁。这通常是状态栏文字颜色设置与页面背景变化不同步导致的。解决思路是,把状态栏文字颜色的变更和页面背景色的切换放在同一个状态回调里,尽量不要一前一后触发。
6.3 深色切换后页面不刷新的几个真实案例
我遇到过的案例里,最典型的就是代码里硬编码颜色。比如某个卡片背景色直接写 Color.White,深色模式下它依然是白色,突兀地插在深色页面里。这个问题的排查思路是全局搜索代码中的颜色常量,把硬编码颜色全部替换为资源引用。
第二个典型问题是 Canvas 绘制内容没有刷新。有些图表或图形组件是在 Canvas 里直接绘制的,绘制时读取了颜色值。切换深浅色后,组件虽然重建了,但绘制逻辑读取的还是旧的缓存数据。这种问题需要在配置更新回调里主动触发一次重绘,或者给 Canvas 组件加一个绑定当前颜色模式的状态变量。
第三个问题是自定义弹窗或者子窗口不跟随页面刷新。深色模式切换后,弹窗的背景色还是旧的。原因是弹窗通常挂载在独立的窗口或者节点上,资源引用没有联动。解决的办法是在弹窗组件内部也使用 $r 资源引用,同时在弹窗显示前重新检查当前颜色模式。
第四个问题比较隐蔽:我遇到过某个页面在深色模式下文字颜色变化了,但图片混合模式后的效果看起来灰蒙蒙的。排查之后发现是因为图片本身是深色系,叠加了默认的白色混合模式,导致图片在深色背景下发灰。这个场景需要根据页面整体效果调整图片的混合模式参数,不能只换资源图片就完事。
关于状态栏文字颜色和深色模式切换这两个方向,我自己也是踩过几次坑才彻底理清的。尤其是状态栏文字颜色,它在沉浸式效果里起到的作用远比想象中大,很多时候页面内容没问题,但就是因为状态栏文字颜色不合适,整个界面看起来就很别扭。建议你在做页面的时候,把沉浸式状态栏的管理单独封装成一个工具类,在页面 onPageShow 里统一调用,避免每个页面都写一套重复的窗口设置代码。
掌握了这套组合玩法之后,再回看自己做过的页面,会发现之前很多“感觉不对”的地方其实都是沉浸式没做透、深色模式没适配到位的表现。勤练习,把资源目录和窗口配置这两块吃透,后面接复杂项目时就能少走不少弯路。
