# 18.13:主题切换
为了更好的用户体验,各大主流应用都逐渐支持了主题切换功能,比如 QQ 支持日间模式和夜间模式的主题切换,本节笔者简单介绍一下如何在 OpenHarmony 上实现主题切换的功能,下图是笔者模仿 QQ 主题切换的演示效果:
# 18.13.1:主题切换原理
主题的切换本质上就是根据用户选择的主题类型,动态的更改页面上组件的相关属性,比如更改页面其背景色,更改文本的颜色等。
用户选择相关主题类型后要做页面的主题刷新,然后把主题类型持久化存储,之后页面就是显示用户选择过的主题进行展示。
主题的更换和持久化牵涉到状态管理的知识点,笔者在第二章第 5 小节讲解过相关实现,读者可自行查阅,笔者就不在过多介绍了。
# 18.13.2:主题数据定义
定义主题数据时,为了防止出现主题数据在各主题模式中缺失的场景,笔者选择了 interface
做为主题的数据集,凡是用到的主题数据都定义在 interface
中,然后各主题模式均实现该 interface
后再分别实现不同的属性值定义。
定义数据类型
因各组件对样式属性要求不一致,比如:对 Text 来说可能只定义文本颜色就可以了,而颜色的定义官方支持
Color
、number
、string
、Resource
,对 Image 来说官方支持string
、PixelMap
和Resource
,因此需要先定义一个主题支持的数据类型,样例代码如下所示: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
6Text 使用了
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;
}
}
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) // 使用主题
}
}
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.4:小结
本节笔者简单介绍了实现主题切换的实现过程,对于多页面主题切换的更新场景读者可参阅笔者可参考第二章第 5 小节的讲解,另外根据文档看,OpenHarmony 默认支持两种主题:light 和 dark,等后续能在设备上做演示了,笔者再补充使用系统主题的实现方式。
← 18.12:屏幕截图 19.1:环境搭建 →