HarmonyOS开发关怀模式:长辈模式的接入、同步与三种思路对比
无障碍技术里,屏幕朗读服务的是视障用户这个相对小众的群体,但"关怀模式"(也叫长辈模式、长辈版、关爱版、大字版)服务的却是海量的老年用户。这是无障碍里离商业价值最近的一块,也是很多互联网产品在做适老化改造时的重点。鸿蒙从 API 26 开始,把关怀模式的接入能力系统化了。这篇讲清楚三种接入思路,以及各自的适用场景。
一、关怀模式要解决什么问题
老年人用手机的核心痛点很集中:字小看不清、图标小点不准、流程复杂记不住。关怀模式就是针对这些痛点做的大字号、大图标、高对比度、简化流程的界面形态。
和屏幕朗读不同,关怀模式不改变交互范式(还是靠"看+点"),而是放大视觉和交互的容错空间。所以它不需要 TTS 引擎,实现成本也低得多——本质就是一套"放大版"的 UI 配置。
鸿蒙把关怀模式做成了一个系统级的能力:设备"设置 → 关怀和无障碍 → 关怀模式"里有个总开关,还有"应用管理",可以针对每个应用单独控制关怀模式。
二、三种接入思路总览
官方文档提供了三种接入思路,对应不同的产品诉求:
| 思路 | 适用场景 | 核心接口/配置 |
|---|---|---|
| 1. 声明接入,独立控制 | 应用有自己的关怀模式开关,且希望暴露到系统设置里统一管理 | module.json5 的 metadata 声明 |
| 2. 应用内开关与系统同步 | 应用内有独立开关,但要和系统"应用管理"页保持双向同步 | getSeniorModeStateForSelf / setSeniorModeStateForSelf 等 |
| 3. 跟随系统,不自带开关 | 应用没有独立开关,完全跟随系统关怀模式 | isSeniorModeEnabled / onSeniorModeStateChange |
先想清楚你属于哪种,再选接口,能少走很多弯路。
三、思路一:声明接入,让应用出现在系统设置里
如果你的应用已经自己实现了关怀模式(有独立的开关和 UI),想把它接入系统,方便用户在"设置 → 关怀模式 → 应用管理"里统一查看和切换,那只需要在 module.json5 里加一段 metadata 声明。
从 API 26.0.0 开始,在对应 module 的 metadata 里声明:
{
"module": {
"metadata": [{
"name": "senior_mode",
"value": "independent_control"
}]
}
}
声明之后,用户的设备"设置 → 关怀和无障碍 → 关怀模式 → 应用管理"里就会出现你的应用,用户可以自由切换该应用的关怀模式开关。
这里有个重要的联动行为要记住:
- 用户在设置里关闭系统总开关时,应用内关怀模式也会随之关闭
- 重新开启系统总开关,原先被关闭的应用会同步开启
这个"总开关联动"的设计,保证了用户的操作是一致的——关了系统关怀,所有应用都跟着关,不会出现"系统关了某个应用还开着"的割裂状态。
建议:声明写在有关怀模式功能的那个 module 下,而不是随便哪个 module。
四、思路二:应用内开关与系统双向同步
思路一只是"声明了、能出现",但应用内开关和系统设置里的开关还是两套状态。用户在系统里切了开关,应用内不会自动知道;反之亦然。要打通这两者,需要思路二的接口。
4.1 三个核心接口
| 接口 | 作用 |
|---|---|
getSeniorModeStateForSelf() | 查询系统"应用管理"页里本应用的关怀模式开关状态 |
setSeniorModeStateForSelf(state) | 设置系统"应用管理"页里本应用的开关状态 |
onSeniorModeStateChangeForSelf(cb) | 监听系统"应用管理"页里的开关变化 |
offSeniorModeStateChangeForSelf(cb) | 取消监听 |
注意 ForSelf 这个后缀——这些接口操作的都是当前应用自身在系统设置里的开关,而不是系统总开关。总开关是另一套接口(思路三)。
4.2 完整代码示例
完整的同步逻辑分三步:启动时查询、监听变化、本地切换时上报。
import accessibility from '@ohos.accessibility'
@Entry
@Component
struct Index {
@State state: boolean = false;
callBack = (data: boolean) => {
console.info(`data: ` + data);
this.state = data;
// 应用内关怀模式开启/关闭的 UI 刷新
}
async aboutToAppear(): Promise<void> {
// 1. 注册监听
accessibility.onSeniorModeStateChangeForSelf(this.callBack);
// 2. 启动时查询当前状态
this.state = await accessibility.getSeniorModeStateForSelf();
}
aboutToDisappear(): void {
// 3. 取消监听
accessibility.offSeniorModeStateChangeForSelf(this.callBack);
}
build() {
Column() {
Row() {
Text(`senior mode: ${this.state ? 'open' : 'closed'}`)
.fontSize(18)
Toggle({ type: ToggleType.Switch, isOn: this.state })
.onChange(async (isOn: boolean) => {
if (isOn !== this.state) {
this.state = isOn;
// 应用内切换时,上报给系统保持同步
await accessibility.setSeniorModeStateForSelf(isOn);
}
})
}
}
.height('100%')
.width('100%')
}
}
这段代码体现了三个时机的处理:
aboutToAppear:注册监听 + 查询初始状态(保证一进来就和系统对齐)- 监听回调:系统设置变化时,同步刷新应用内 UI
onChange:应用内用户手动切换时,调用setSeniorModeStateForSelf上报系统
监听的生命周期管理也很规范:aboutToAppear 注册、aboutToDisappear 取消,避免内存泄漏。
五、思路三:跟随系统,不自带开关
如果你的应用不想自己维护关怀模式的状态,完全跟随系统总开关走,那更简单——用系统总开关的查询和监听接口。
5.1 核心接口
| 接口 | 作用 |
|---|---|
isSeniorModeEnabled() | 查询系统关怀模式总开关状态 |
onSeniorModeStateChange(cb) | 监听系统总开关变化 |
offSeniorModeStateChange(cb) | 取消监听 |
注意和思路二的区别:这里没有 ForSelf 后缀,操作的是系统全局关怀模式,不是"本应用"。
5.2 代码示例:监听系统总开关
import { accessibility } from '@kit.AccessibilityKit';
@Entry
@Component
struct SeniorModeDemo {
callback = (data: boolean) => {
console.info(`senior mode changed: ${JSON.stringify(data)}`);
// data 为 true 表示系统关怀模式已打开
}
aboutToAppear(): void {
accessibility.onSeniorModeStateChange(this.callback);
}
aboutToDisappear(): void {
accessibility.offSeniorModeStateChange(this.callback);
}
build() {
// 自行展示 UX 界面
}
}
5.3 代码示例:查询系统总开关
import { accessibility } from '@kit.AccessibilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct SeniorModeQuery {
aboutToAppear(): void {
accessibility.isSeniorModeEnabled()
.then((data: boolean) => {
console.info(`isSeniorModeEnabled: ${JSON.stringify(data)}`);
})
.catch((err: BusinessError) => {
console.error(`failed, code: ${err.code}, message: ${err.message}`);
});
}
build() {
// 自行展示 UX 界面
}
}
5.4 导入方式的一个细节
思路三的示例用的是 import { accessibility } from '@kit.AccessibilityKit',而思路二用的是 import accessibility from '@ohos.accessibility'。两种导入方式都存在于官方文档里。实际项目里,建议统一用 Kit 化的导入方式 @kit.AccessibilityKit,这是新版本推荐的风格,也和前几篇文章的 accessibility 用法保持一致。
六、怎么选:一张决策图
三种思路的选择,本质是回答两个问题:
-
我的应用有独立的关怀模式开关吗?
- 有 → 思路二(或思路一 + 思路二组合)
- 没有 → 思路三
-
我希望关怀模式能在系统的"应用管理"里被用户看到和控制吗?
- 希望 → 先做思路一的 metadata 声明,再做思路二的同步
- 无所谓,跟系统走就行 → 思路三
大多数做了适老化改造的成熟应用,最终都会走到"思路一 + 思路二"的组合:声明接入、双向同步。因为这样才能既在系统里统一管理,又保证应用内外的状态一致。
七、几个开发注意事项
7.1 版本门槛
这一整套关怀模式接口都是 API 26.0.0 才有的。如果你的目标 SDK 低于 26,这些接口不可用。动手前先确认工程的 API 版本。
7.2 监听要及时注销
onSeniorModeStateChangeForSelf 和 onSeniorModeStateChange 注册的监听,一定要在组件销毁时(aboutToDisappear)注销。否则会造成内存泄漏和重复回调。
7.3 状态初始化的时机
应用冷启动时,aboutToAppear 里先查询一次状态、再注册监听,能避免"启动瞬间用了过期状态"的问题。查询和监听谁先谁后,取决于你能否容忍初始态的短暂空窗。
7.4 UI 刷新要解耦
关怀模式切换会带来大面积的 UI 变化(字号、间距、布局)。建议用一个全局状态(如 AppStorage)承载关怀模式开关,各组件订阅这个状态来刷新,而不是每个组件都自己去调 accessibility 接口。这样状态来源单一,刷新也好控制。
八、总结一下下
关怀模式是无障碍里最"接地气"的一环。三种思路可以浓缩成一句话:
- 有自己的开关 + 想进系统设置:声明 metadata + 用
ForSelf系列接口做双向同步 - 没自己的开关:用
isSeniorModeEnabled/onSeniorModeStateChange跟随系统总开关
记住接口的命名规律就不会混:带 ForSelf 的是"本应用"的开关,不带的是"系统总开关"。
更多推荐



所有评论(0)