HarmonyOS AppUtil 应用配置控制:颜色模式/灰度/字体/语言/键盘避让详解

文章目录

    • 前言
    • [一、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())
    • [二、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 返回 booleantrue 表示设置成功。

二、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 两种

这几个接口覆盖了日常应用外观和交互体验的大多数配置场景,封装后调用非常简洁。

相关推荐
FrameNotWork2 小时前
HarmonyOS 6.1 Lottie动画集成完全指南:从踩坑到精通
华为·harmonyos
三声三视2 小时前
Electron 本地图片在鸿蒙 PC 上白图,我注册了个自定义协议
electron·harmonyos·鸿蒙
李二。2 小时前
日历日程管理工具 — 基于 HarmonyOS NEXT (API 23+) 的 ArkTS 纯声明式实现
华为·harmonyos
金启攻3 小时前
鸿蒙原生应用实战(三):搜索与详情页 —— 多维度筛选与动态路由
华为·harmonyos
祭曦念4 小时前
鸿蒙原生Gauge仪表盘组件深度实践
华为·harmonyos
风华圆舞4 小时前
DevEco Studio 和 Flutter 工具链如何协同工作
flutter·华为·架构·harmonyos
祭曦念4 小时前
鸿蒙Next实战:从零构建每日打卡应用
华为·harmonyos
yuegu7774 小时前
HarmonyOS应用<节气通>开发第20篇:ArticleCard组件封装
华为·harmonyos
金启攻4 小时前
鸿蒙原生应用实战(二):首页开发 —— 周历导航与@Builder组件化实践
华为·harmonyos