文章目录
-
- 前言
- [一、AppUtil 应用配置方法详解](#一、AppUtil 应用配置方法详解)
-
- [1. `setColorMode(colorMode)` / `getColorMode()`](#1.
setColorMode(colorMode)/getColorMode()) - [2. `setGrayScale(grayScale, onlyMainWindow?)` / 无对应 get(实时设置)](#2.
setGrayScale(grayScale, onlyMainWindow?)/ 无对应 get(实时设置)) - [3. `setFontSizeScale(fontSizeScale)` / `getFontSizeScale()`](#3.
setFontSizeScale(fontSizeScale)/getFontSizeScale()) - [4. `setLanguage(language)` / `getLanguage()`](#4.
setLanguage(language)/getLanguage()) - [5. `setKeyboardAvoidMode(value)` / `getKeyboardAvoidMode()`](#5.
setKeyboardAvoidMode(value)/getKeyboardAvoidMode())
- [1. `setColorMode(colorMode)` / `getColorMode()`](#1.
- [二、Demo 代码演示](#二、Demo 代码演示)
- 三、代码讲解
-
- [3.1 初始化时读取当前状态](#3.1 初始化时读取当前状态)
- [3.2 灰度 Slider 的处理技巧](#3.2 灰度 Slider 的处理技巧)
- [3.3 字体缩放与 UI 实时预览联动](#3.3 字体缩放与 UI 实时预览联动)
- [3.4 键盘避让模式的区别](#3.4 键盘避让模式的区别)
- 四、一键置灰最佳实践
- 五、小结
前言
近期发现一款很有意思的HarmonyOS 三方库, 地址 @pura/harmony-utils(V1.4.0) , 作者是"桃花镇童长老", 我这里也是直接通过该作者公布的源码进行案例编写进行, 目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦

案例demo导航展示

↓↓↓↓↓↓接下来言归正传 ↓↓↓↓
很多 App 都有这些需求:
- 哀悼日或特殊场景下,一键把整个 App 变成灰度
- 适配系统的深色模式 / 浅色模式
- 让用户调整 App 内字体大小
- 切换应用语言,不重启 App 就生效
- 控制键盘弹起时内容是被压缩还是被顶上去
AppUtil 对这些配置能力都做了封装,本文结合 AppConfigDemoPage.ets 完整 Demo 代码逐一讲解。
一、AppUtil 应用配置方法详解
1. setColorMode(colorMode) / getColorMode()
作用: 设置/获取应用颜色模式。
typescript
static setColorMode(colorMode: ConfigurationConstant.ColorMode): void
static getColorMode(): ConfigurationConstant.ColorMode
参数说明:
| colorMode 值 | 含义 |
|---|---|
COLOR_MODE_LIGHT |
浅色模式 |
COLOR_MODE_DARK |
深色模式 |
COLOR_MODE_NOT_SET |
跟随系统 |
说明: 调用 setColorMode 后立即生效,整个应用的颜色主题会切换。getColorMode 返回当前模式枚举值。
2. setGrayScale(grayScale, onlyMainWindow?) / 无对应 get(实时设置)
作用: 设置整个应用的灰度值(置灰效果)。
typescript
static setGrayScale(grayScale: number, onlyMainWindow?: boolean): void
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| grayScale | number | 灰度值,范围 0.0(彩色)~ 1.0(完全灰度) |
| onlyMainWindow | boolean | 可选,是否只对主窗口生效,默认 false |
说明: 1.0 就是哀悼日常见的"全灰"效果,0 恢复彩色。
3. setFontSizeScale(fontSizeScale) / getFontSizeScale()
作用: 设置/获取应用字体缩放比例(需要 API 13+)。
typescript
static setFontSizeScale(fontSizeScale: number): void
static getFontSizeScale(): number
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| fontSizeScale | number | 字体缩放比例,1.0 为默认大小,0.5 为一半,2.0 为两倍 |
说明: 设置后仅对应用内生效,不影响系统字体。调用前建议先用 AppUtil.isApiSupported(13) 确认支持。
4. setLanguage(language) / getLanguage()
作用: 设置/获取应用语言。
typescript
static setLanguage(language: string): void
static getLanguage(): string
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| language | string | 语言标签,如 "zh-Hans"(简体中文)、"en"(英语)、"zh-Hant"(繁体中文) |
说明: 修改后应用内多语言资源会跟着切换,不需要重启。
5. setKeyboardAvoidMode(value) / getKeyboardAvoidMode()
作用: 设置/获取键盘弹起时的避让模式。
typescript
static setKeyboardAvoidMode(value: KeyboardAvoidMode): boolean
static getKeyboardAvoidMode(): KeyboardAvoidMode
参数说明:
| KeyboardAvoidMode 值 | 含义 |
|---|---|
OFFSET |
上抬模式:键盘弹起时,整个页面往上移动 |
RESIZE |
压缩模式:键盘弹起时,页面高度被压缩 |
返回值: setKeyboardAvoidMode 返回 boolean,true 表示设置成功。
二、Demo 代码演示
案例效果展示


typescript
import router from '@ohos.router';
import { ConfigurationConstant } from '@kit.AbilityKit';
import { KeyboardAvoidMode } from '@kit.ArkUI';
import { AppUtil } from '../Utils/AppUtil';
/**
* Demo 2: 应用配置控制
* 演示颜色模式切换、灰阶置灰、字体大小缩放、语言设置、键盘避让模式
*/
@Entry
@Component
struct AppConfigDemoPage {
@State grayScale: number = 0;
@State fontSizeScale: number = 1.0;
@State currentColorMode: string = '跟随系统';
@State currentLanguage: string = '';
@State currentKeyboardMode: string = '';
@State statusMsg: string = '';
aboutToAppear(): void {
// 读取当前状态
const cm = AppUtil.getColorMode();
if (cm === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
this.currentColorMode = '深色模式';
} else if (cm === ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT) {
this.currentColorMode = '浅色模式';
} else {
this.currentColorMode = '跟随系统';
}
const lang = AppUtil.getLanguage();
this.currentLanguage = lang ?? '未设置';
const fs = AppUtil.getFontSizeScale();
this.fontSizeScale = fs ?? 1.0;
try {
const km = AppUtil.getKeyboardAvoidMode();
this.currentKeyboardMode = km === KeyboardAvoidMode.RESIZE ? 'RESIZE(压缩)' : 'OFFSET(上抬)';
} catch (e) {
this.currentKeyboardMode = '获取失败';
}
}
showMsg(msg: string) {
this.statusMsg = msg;
setTimeout(() => {
this.statusMsg = '';
}, 2000);
}
build() {
Column() {
// 顶部导航
Row() {
Image($r('sys.media.ohos_ic_back'))
.width(24)
.height(24)
.onClick(() => router.back())
Text('应用配置控制')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#1a1a1a')
.margin({ left: 12 })
}
.width('100%')
.height(56)
.padding({ left: 16, right: 20 })
.backgroundColor('#FFFFFF')
Scroll() {
Column({ space: 12 }) {
// ── 颜色模式 ──────────────────────────────────────────────
Column() {
Text('🌗 颜色模式切换')
.fontSize(14).fontColor('#666').fontWeight(FontWeight.Medium)
.alignSelf(ItemAlign.Start).margin({ bottom: 4 })
Text(`当前: ${this.currentColorMode}`)
.fontSize(12).fontColor('#999').alignSelf(ItemAlign.Start).margin({ bottom: 12 })
Row({ space: 8 }) {
Button('浅色').layoutWeight(1).height(36).borderRadius(8)
.backgroundColor('#F5F6FA').fontColor('#333').fontSize(13)
.onClick(() => {
AppUtil.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
this.currentColorMode = '浅色模式';
this.showMsg('已切换为浅色模式');
})
Button('深色').layoutWeight(1).height(36).borderRadius(8)
.backgroundColor('#222').fontColor('#FFF').fontSize(13)
.onClick(() => {
AppUtil.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK);
this.currentColorMode = '深色模式';
this.showMsg('已切换为深色模式');
})
Button('跟随系统').layoutWeight(1).height(36).borderRadius(8)
.backgroundColor('#4080FF').fontColor('#FFF').fontSize(13)
.onClick(() => {
AppUtil.setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
this.currentColorMode = '跟随系统';
this.showMsg('已设置跟随系统');
})
}
}
.width('100%').padding(16).backgroundColor('#FFFFFF').borderRadius(12)
// ── 灰阶置灰 ──────────────────────────────────────────────
Column() {
Text('🖤 一键置灰 (setGrayScale)')
.fontSize(14).fontColor('#666').fontWeight(FontWeight.Medium)
.alignSelf(ItemAlign.Start).margin({ bottom: 4 })
Text(`灰阶值: ${this.grayScale.toFixed(1)} (0=彩色 / 1=完全灰度)`)
.fontSize(12).fontColor('#999').alignSelf(ItemAlign.Start).margin({ bottom: 8 })
Slider({
value: this.grayScale * 10,
min: 0,
max: 10,
step: 1,
style: SliderStyle.OutSet
})
.width('100%')
.onChange((value: number) => {
this.grayScale = value / 10;
AppUtil.setGrayScale(this.grayScale);
})
Row({ space: 8 }) {
Button('一键变灰').layoutWeight(1).height(36).borderRadius(8)
.backgroundColor('#888').fontColor('#FFF').fontSize(13)
.onClick(() => {
this.grayScale = 1.0;
AppUtil.setGrayScale(1.0);
this.showMsg('已置灰');
})
Button('恢复彩色').layoutWeight(1).height(36).borderRadius(8)
.backgroundColor('#4080FF').fontColor('#FFF').fontSize(13)
.onClick(() => {
this.grayScale = 0;
AppUtil.setGrayScale(0);
this.showMsg('已恢复彩色');
})
}
.margin({ top: 8 })
}
.width('100%').padding(16).backgroundColor('#FFFFFF').borderRadius(12)
// ── 字体大小缩放 ──────────────────────────────────────────
Column() {
Text('🔤 字体大小缩放 (API 13+)')
.fontSize(14).fontColor('#666').fontWeight(FontWeight.Medium)
.alignSelf(ItemAlign.Start).margin({ bottom: 4 })
Text(`当前缩放比例: ${this.fontSizeScale.toFixed(1)}x`)
.fontSize(12).fontColor('#999').alignSelf(ItemAlign.Start).margin({ bottom: 8 })
Slider({
value: this.fontSizeScale * 10,
min: 5,
max: 20,
step: 1,
style: SliderStyle.OutSet
})
.width('100%')
.onChange((value: number) => {
this.fontSizeScale = value / 10;
AppUtil.setFontSizeScale(this.fontSizeScale);
})
// 预览字体效果
Text(`预览文字大小效果 ${this.fontSizeScale.toFixed(1)}x`)
.fontSize(14 * this.fontSizeScale)
.fontColor('#1a1a1a')
.margin({ top: 12 })
Button('重置 1.0x').width('100%').height(36).borderRadius(8).margin({ top: 8 })
.backgroundColor('#F5F6FA').fontColor('#333').fontSize(13)
.onClick(() => {
this.fontSizeScale = 1.0;
AppUtil.setFontSizeScale(1.0);
this.showMsg('字体已重置');
})
}
.width('100%').padding(16).backgroundColor('#FFFFFF').borderRadius(12)
// ── 语言设置 ──────────────────────────────────────────────
Column() {
Text('🌏 语言设置 (setLanguage)')
.fontSize(14).fontColor('#666').fontWeight(FontWeight.Medium)
.alignSelf(ItemAlign.Start).margin({ bottom: 4 })
Text(`当前语言: ${this.currentLanguage}`)
.fontSize(12).fontColor('#999').alignSelf(ItemAlign.Start).margin({ bottom: 12 })
Row({ space: 8 }) {
Button('中文 zh-Hans').layoutWeight(1).height(36).borderRadius(8)
.backgroundColor('#F5F6FA').fontColor('#333').fontSize(12)
.onClick(() => {
AppUtil.setLanguage('zh-Hans');
this.currentLanguage = 'zh-Hans';
this.showMsg('已设置简体中文');
})
Button('English en').layoutWeight(1).height(36).borderRadius(8)
.backgroundColor('#F5F6FA').fontColor('#333').fontSize(12)
.onClick(() => {
AppUtil.setLanguage('en');
this.currentLanguage = 'en';
this.showMsg('已设置英文');
})
}
}
.width('100%').padding(16).backgroundColor('#FFFFFF').borderRadius(12)
// ── 键盘避让模式 ──────────────────────────────────────────
Column() {
Text('⌨️ 键盘避让模式')
.fontSize(14).fontColor('#666').fontWeight(FontWeight.Medium)
.alignSelf(ItemAlign.Start).margin({ bottom: 4 })
Text(`当前模式: ${this.currentKeyboardMode}`)
.fontSize(12).fontColor('#999').alignSelf(ItemAlign.Start).margin({ bottom: 12 })
Row({ space: 8 }) {
Button('OFFSET(上抬)').layoutWeight(1).height(36).borderRadius(8)
.backgroundColor('#F5F6FA').fontColor('#333').fontSize(12)
.onClick(() => {
const ok = AppUtil.setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET);
if (ok) {
this.currentKeyboardMode = 'OFFSET(上抬)';
this.showMsg('已设置上抬模式');
}
})
Button('RESIZE(压缩)').layoutWeight(1).height(36).borderRadius(8)
.backgroundColor('#4080FF').fontColor('#FFF').fontSize(12)
.onClick(() => {
const ok = AppUtil.setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE);
if (ok) {
this.currentKeyboardMode = 'RESIZE(压缩)';
this.showMsg('已设置压缩模式');
}
})
}
// 测试输入框:演示键盘弹起效果
TextInput({ placeholder: '点击此处弹起键盘,观察避让效果' })
.width('100%')
.height(44)
.margin({ top: 12 })
.borderRadius(8)
}
.width('100%').padding(16).backgroundColor('#FFFFFF').borderRadius(12)
// 消息提示
if (this.statusMsg !== '') {
Text(this.statusMsg)
.fontSize(13).fontColor('#4080FF')
.backgroundColor('#EEF3FF')
.padding({ left: 16, right: 16, top: 10, bottom: 10 })
.borderRadius(8)
.width('100%')
.textAlign(TextAlign.Center)
}
// 底部留白
Blank().height(24)
}
.padding(16)
}
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor('#F5F6FA')
}
}
三、代码讲解
3.1 初始化时读取当前状态
页面一打开就在 aboutToAppear 里把当前的配置状态读出来展示给用户,让用户知道"现在处于什么状态",这是一个好习惯:
typescript
const cm = AppUtil.getColorMode();
// 根据返回值映射到中文描述
if (cm === ConfigurationConstant.ColorMode.COLOR_MODE_DARK) {
this.currentColorMode = '深色模式';
} else if (cm === ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT) {
this.currentColorMode = '浅色模式';
} else {
this.currentColorMode = '跟随系统';
}
3.2 灰度 Slider 的处理技巧
setGrayScale 接收的是 0.0 ~ 1.0 之间的浮点数,但 Slider 的 min/max/step 不好直接用小数。Demo 里用的是"放大 10 倍"的技巧:
typescript
Slider({
value: this.grayScale * 10, // 将 0~1 映射到 0~10
min: 0,
max: 10,
step: 1,
})
.onChange((value: number) => {
this.grayScale = value / 10; // 再除以 10 还原回 0~1
AppUtil.setGrayScale(this.grayScale);
})
3.3 字体缩放与 UI 实时预览联动
字体缩放的 Slider 和下面的预览文字是联动的。fontSizeScale 既用于控制 Slider 的值,也直接乘以基础字号来改变文字大小,实现所见即所得:
typescript
Text(`预览文字大小效果 ${this.fontSizeScale.toFixed(1)}x`)
.fontSize(14 * this.fontSizeScale) // 动态字号
3.4 键盘避让模式的区别
- OFFSET(上抬):键盘弹起时整个页面整体向上位移,底部输入框不会被遮挡,但可能导致顶部内容移出屏幕外。
- RESIZE(压缩):键盘弹起时可视区域被压缩,内容在剩余空间内重新布局。
根据页面结构选择合适的模式。有固定底部输入框的聊天页面通常用 OFFSET,有大量内容的表单页面用 RESIZE。
四、一键置灰最佳实践
哀悼日一键置灰的正确写法:
typescript
// 在 App 启动时或特殊日期判断后调用
AppUtil.setGrayScale(1.0); // 全灰
// 恢复
AppUtil.setGrayScale(0); // 彩色
如果只想对主窗口置灰(子窗口保持彩色),传第二个参数:
typescript
AppUtil.setGrayScale(1.0, true); // 仅主窗口灰度
五、小结
| 方法 | 作用 | 注意事项 |
|---|---|---|
setColorMode / getColorMode |
深色/浅色/跟随系统 | 立即生效 |
setGrayScale |
灰度置灰 | 范围 0.0~1.0 |
setFontSizeScale / getFontSizeScale |
字体缩放 | 需要 API 13+ |
setLanguage / getLanguage |
应用语言 | 无需重启 |
setKeyboardAvoidMode / getKeyboardAvoidMode |
键盘避让 | OFFSET/RESIZE 两种 |
这几个接口覆盖了日常应用外观和交互体验的大多数配置场景,封装后调用非常简洁。