# 18.13:主题切换

为了更好的用户体验,各大主流应用都逐渐支持了主题切换功能,比如 QQ 支持日间模式和夜间模式的主题切换,本节笔者简单介绍一下如何在 OpenHarmony 上实现主题切换的功能,下图是笔者模仿 QQ 主题切换的演示效果:

18_13_1

# 18.13.1:主题切换原理

主题的切换本质上就是根据用户选择的主题类型,动态的更改页面上组件的相关属性,比如更改页面其背景色,更改文本的颜色等。

用户选择相关主题类型后要做页面的主题刷新,然后把主题类型持久化存储,之后页面就是显示用户选择过的主题进行展示。

主题的更换和持久化牵涉到状态管理的知识点,笔者在第二章第 5 小节讲解过相关实现,读者可自行查阅,笔者就不在过多介绍了。

# 18.13.2:主题数据定义

定义主题数据时,为了防止出现主题数据在各主题模式中缺失的场景,笔者选择了 interface 做为主题的数据集,凡是用到的主题数据都定义在 interface 中,然后各主题模式均实现该 interface 后再分别实现不同的属性值定义。

  • 定义数据类型

    因各组件对样式属性要求不一致,比如:对 Text 来说可能只定义文本颜色就可以了,而颜色的定义官方支持 ColornumberstringResource,对 Image 来说官方支持 stringPixelMapResource,因此需要先定义一个主题支持的数据类型,样例代码如下所示:

    declare type THEME = Resource | string | Color;
    
    1
  • 定义主题接口

    interface Theme {
      BG_COLOR: THEME;
    }
    
    1
    2
    3

    📢: Theme 是应用支持的样式集合,为了防止样式遗漏,所有参与样式的展示都要求定义在这里。

  • 实现主题接口

    定义完 Theme 接口后,分别实现日间模式和夜间模式的主题,样例代码如下所示:

    // 日间模式
    class LightTheme implements Theme {
      BG_COLOR = "#eeeeee";
    }
    
    // 夜间模式
    class NightTheme implements Theme {
      BG_COLOR = "#111111";
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  • 获取主题方法

    function getTheme(theme: number): Theme {
      let key = "app_global_theme_" + theme;
      var cachedTheme = DataManager.getDataSource().getData(key, null);
      if (!cachedTheme) {
        cachedTheme = (0 == theme ? new LightTheme() : new NightTheme());
        DataManager.getDataSource().putData(key, cachedTheme);
      }
      return cachedTheme as Theme;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    为了防止过多的创建 Theme 实例,笔者使用 DataManager 做了缓存,有关 DataManager 的具体使用和实现,读者可查阅本章 第 9 小节

  • 主题切换实现

    定义完 getTheme() 方法后,就可以在需要更换主题的组件上使用该方法了,样例代码如下所示:

    Text("切换主题")
      .fontSize(24)
      .width(120)
      .height(45)
      .fontColor(getTheme(this.theme).Text_COLOR);         // 使用主题
      .backgroundColor(theme.getTheme(this.theme).Text_BG) // 使用主题
    
    1
    2
    3
    4
    5
    6

    Text 使用了 getTheme() 方法获设置当前文本颜色,当用户切换到其它主题时会自动更新到对应的主题颜色。

# 18.13.3:完整样例

主题是一个比较独立的功能,笔者把它定义在了一个独立的 theme.ets 文件里,完整代码如下所示:

// theme.ets 文件
export namespace theme {

  declare type THEME = Resource | string | Color;

  export interface Theme {
    BG_COLOR: THEME;
    Text_COLOR: THEME;
    Text_BG: THEME;
  }

  class LightTheme implements Theme {
    BG_COLOR = "#eeeeee";
    Text_COLOR = Color.Black;
    Text_BG = Color.Pink;
  }

  class NightTheme implements Theme {
    BG_COLOR = "#111111";
    Text_COLOR = Color.White;
    Text_BG = Color.Orange;
  }

  export function getTheme(theme: number): Theme {
    let key = "app_global_theme_" + theme;
    var cachedTheme = DataManager.getDataSource().getData(key, null);
    if (!cachedTheme) {
      cachedTheme = (0 == theme ? new LightTheme() : new NightTheme());
      DataManager.getDataSource().putData(key, cachedTheme);
    }
    return cachedTheme as Theme;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

然后在需要切换主题的的页面里就可以使用该主题功能了,样例代码如下所示:

import {theme} from "./skin/theme"

@Entry @Component struct ArkUIClubThemeTest {

  @State theme: number = 0;

  build() {
    Stack() {
      Text("切换主题")
        .fontSize(24)
        .width(150)
        .height(65)
        .fontColor(theme.getTheme(this.theme).Text_COLOR)   // 使用主题
        .borderRadius(8)
        .textAlign(TextAlign.Center)
        .backgroundColor(theme.getTheme(this.theme).Text_BG)// 使用主题
        .onClick(() => {
          this.theme = 0 == this.theme ? 1 : 0;
        })

      Image($r("app.media.bg1"))
        .width("100%")
        .height("100%")
        .enabled(false)
    }
    .width("100%")
    .height("100%")
    .padding(20)
    .backgroundColor(theme.getTheme(this.theme).BG_COLOR)   // 使用主题
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

样例运行结果如下图所示:

18_13_3_1

# 18.13.4:小结

本节笔者简单介绍了实现主题切换的实现过程,对于多页面主题切换的更新场景读者可参阅笔者可参考第二章第 5 小节的讲解,另外根据文档看,OpenHarmony 默认支持两种主题:lightdark,等后续能在设备上做演示了,笔者再补充使用系统主题的实现方式。

(adsbygoogle = window.adsbygoogle || []).push({});
请作者喝杯咖啡

津公网安备 12011402001367号

津ICP备2020008934号-2

中央网信办互联网违法和不良信息举报中心

天津市互联网违法和不良信息举报中心