1# 设置应用内主题换肤 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @lushi871202--> 5<!--Designer: @lushi871202--> 6<!--Tester: @sally__--> 7<!--Adviser: @HelloCrease--> 8 9## 概述 10 11对于采用ArkTS开发的应用,提供了应用内组件的主题换肤功能,支持局部的深浅色切换及动态换肤。目前,该功能只支持设置应用内主题换肤,暂不支持在UIAbility或窗口层面进行主题设置,同时也不支持C-API和Node-API。 12 13## 自定义主题色 14当应用需要使用换肤功能时,应自定义主题颜色。[CustomTheme](../reference/apis-arkui/js-apis-arkui-theme.md#customtheme)用于自定义主题色的内容,其属性可选,仅需要复写需修改的部分,未修改内容将继承系统默认设置,可参考[系统默认的token颜色值](#系统缺省token色值)。请参照以下示例自定义主题色: 15 16 ```ts 17 // AppTheme.ets 18 import { CustomColors, CustomTheme } from '@kit.ArkUI'; 19 20 export class AppColors implements CustomColors { 21 // 自定义主题色 22 brand: ResourceColor = '#FF75D9'; 23 // 使用$r,让一级警示色在深色和浅色模式下,设置为不同的颜色 24 warning: ResourceColor = $r('app.color.start_window_background'); 25 } 26 27 export class AppTheme implements CustomTheme { 28 public colors: AppColors = new AppColors(); 29 } 30 31 export let gAppTheme: CustomTheme = new AppTheme(); 32 ``` 33 34## 设置应用内组件自定义主题色 35- 可以在页面入口处统一设置应用内组件自定义主题色,但需确保在页面build前执行[ThemeControl](../reference/apis-arkui/js-apis-arkui-theme.md#themecontrol)。 36 其中,[onWillApplyTheme](../reference/apis-arkui/arkui-ts/ts-custom-component-lifecycle.md#onwillapplytheme12)回调函数用于使自定义组件获取当前生效的Theme对象。 37 38 ```ts 39 // Index.ets 40 import { Theme, ThemeControl } from '@kit.ArkUI'; 41 import { gAppTheme } from './AppTheme'; 42 43 //在页面build前执行ThemeControl 44 ThemeControl.setDefaultTheme(gAppTheme); 45 46 @Entry 47 @Component 48 struct DisplayPage { 49 @State menuItemColor: ResourceColor = $r('sys.color.background_primary'); 50 51 onWillApplyTheme(theme: Theme) { 52 this.menuItemColor = theme.colors.backgroundPrimary; 53 } 54 55 build() { 56 Column() { 57 List({ space: 10 }) { 58 ListItem() { 59 Column({ space: '5vp' }) { 60 Text('Color mode') 61 .margin({ top: '5vp', left: '14fp' }) 62 .width('100%') 63 Row() { 64 Column() { 65 Text('Light') 66 .fontSize('16fp') 67 .textAlign(TextAlign.Start) 68 .alignSelf(ItemAlign.Center) 69 Radio({ group: 'light or dark', value: 'light' }) 70 .checked(true) 71 } 72 .width('50%') 73 74 Column() { 75 Text('Dark') 76 .fontSize('16fp') 77 .textAlign(TextAlign.Start) 78 .alignSelf(ItemAlign.Center) 79 Radio({ group: 'light or dark', value: 'dark' }) 80 } 81 .width('50%') 82 } 83 } 84 .width('100%') 85 .height('90vp') 86 .borderRadius('10vp') 87 .backgroundColor(this.menuItemColor) 88 } 89 90 ListItem() { 91 Column() { 92 Text('Brightness') 93 .width('100%') 94 .margin({ top: '5vp', left: '14fp' }) 95 Slider({ value: 40, max: 100 }) 96 } 97 .width('100%') 98 .height('70vp') 99 .borderRadius('10vp') 100 .backgroundColor(this.menuItemColor) 101 } 102 103 ListItem() { 104 Column() { 105 Row() { 106 Column({ space: '5vp' }) { 107 Text('Touch sensitivity') 108 .fontSize('16fp') 109 .textAlign(TextAlign.Start) 110 .width('100%') 111 Text('Increase the touch sensitivity of your screen' + 112 ' for use with screen protectors') 113 .fontSize('12fp') 114 .fontColor(Color.Blue) 115 .textAlign(TextAlign.Start) 116 .width('100%') 117 } 118 .alignSelf(ItemAlign.Center) 119 .margin({ left: '14fp' }) 120 .width('75%') 121 122 Toggle({ type: ToggleType.Switch, isOn: true }) 123 .margin({ right: '14fp' }) 124 .alignSelf(ItemAlign.Center) 125 } 126 .width('100%') 127 .height('80vp') 128 } 129 .width('100%') 130 .borderRadius('10vp') 131 .backgroundColor(this.menuItemColor) 132 } 133 ListItem() { 134 Column() { 135 Text('Warning') 136 .width('100%') 137 .margin({ top: '5vp', left: '14fp' }) 138 Button() { 139 Text('Text') 140 .fontSize(30) 141 .fontWeight(FontWeight.Bold) 142 } 143 .type(ButtonType.Capsule) 144 .role(ButtonRole.ERROR) 145 .width('40%') 146 } 147 .width('100%') 148 .height('70vp') 149 .borderRadius('10vp') 150 } 151 } 152 } 153 .padding('10vp') 154 .backgroundColor('#dcdcdc') 155 .width('100%') 156 .height('100%') 157 } 158 } 159 ``` 160 161- 在UIAbility中设置[ThemeControl](../reference/apis-arkui/js-apis-arkui-theme.md#themecontrol),需要在onWindowStageCreate()方法中[setDefaultTheme](../reference/apis-arkui/js-apis-arkui-theme.md#setdefaulttheme),设置应用内组件的自定义主题色。 162 163 ```ts 164 // EntryAbility.ets 165 import {AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; 166 import { hilog } from '@kit.PerformanceAnalysisKit'; 167 import { window, CustomColors, ThemeControl } from '@kit.ArkUI'; 168 169 class AppColors implements CustomColors { 170 fontPrimary = 0xFFD53032; 171 iconOnPrimary = 0xFFD53032; 172 iconFourth = 0xFFD53032; 173 } 174 175 const abilityThemeColors = new AppColors(); 176 177 export default class EntryAbility extends UIAbility { 178 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 179 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 180 } 181 182 onDestroy() { 183 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); 184 } 185 186 onWindowStageCreate(windowStage: window.WindowStage) { 187 // Main window is created, set main page for this ability 188 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); 189 190 windowStage.loadContent('pages/Index', (err, data) => { 191 if (err.code) { 192 hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 193 return; 194 } 195 hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 196 // 在onWindowStageCreate()方法中setDefaultTheme 197 ThemeControl.setDefaultTheme({ colors: abilityThemeColors }); 198 hilog.info(0x0000, 'testTag', '%{public}s', 'ThemeControl.setDefaultTheme done'); 199 }); 200 } 201 202 } 203 ``` 204 205 206 207> **说明:** 208> 209>如果setDefaultTheme的参数为undefined时,默认token值对应的色值参考[系统缺省token色值](#系统缺省token色值)。 210> 211>setDefaultTheme需要在ArkUI初始化后即windowStage.loadContent的完成时回调中使用。 212 213## 设置应用局部页面自定义主题风格 214通过设置[WithTheme](../reference/apis-arkui/arkui-ts/ts-container-with-theme.md),将自定义主题Theme的配色应用于内部组件的默认样式。在WithTheme的作用范围内,组件的配色会根据Theme的配色进行调整。 215 216如示例所示,使用WithTheme({ theme: this.myTheme })可将作用域内组件的配色设置为自定义主题风格。后续可以通过更新this.myTheme来更换主题风格。[onWillApplyTheme](../reference/apis-arkui/arkui-ts/ts-custom-component-lifecycle.md#onwillapplytheme12)回调函数用于使自定义组件能够获取当前生效的Theme对象。 217 218 ```ts 219 import { CustomColors, CustomTheme, Theme } from '@kit.ArkUI'; 220 221 class AppColors implements CustomColors { 222 fontPrimary: ResourceColor = $r('app.color.brand_purple'); 223 backgroundEmphasize: ResourceColor = $r('app.color.brand_purple'); 224 } 225 226 class AppColorsSec implements CustomColors { 227 fontPrimary: ResourceColor = $r('app.color.brand'); 228 backgroundEmphasize: ResourceColor = $r('app.color.brand'); 229 } 230 231 class AppTheme implements CustomTheme { 232 public colors: AppColors = new AppColors(); 233 } 234 235 class AppThemeSec implements CustomTheme { 236 public colors: AppColors = new AppColorsSec(); 237 } 238 239 @Entry 240 @Component 241 struct DisplayPage { 242 @State customTheme: CustomTheme = new AppTheme(); 243 @State message: string = '设置应用局部页面自定义主题风格'; 244 count = 0; 245 246 build() { 247 WithTheme({ theme: this.customTheme }) { 248 Row(){ 249 Column() { 250 Text('WithTheme') 251 .fontSize(30) 252 .margin({bottom: 10}) 253 Text(this.message) 254 .margin({bottom: 10}) 255 Button('change theme').onClick(() => { 256 this.count++; 257 if (this.count > 1) { 258 this.count = 0; 259 } 260 switch (this.count) { 261 case 0: 262 this.customTheme = new AppTheme(); 263 break; 264 case 1: 265 this.customTheme = new AppThemeSec(); 266 break; 267 } 268 }) 269 } 270 .width('100%') 271 } 272 .height('100%') 273 .width('100%') 274 } 275 } 276 } 277 ``` 278 279 280 281## 设置应用页面局部深浅色 282通过[WithTheme](../reference/apis-arkui/arkui-ts/ts-container-with-theme.md)可以设置三种颜色模式,跟随系统模式,浅色模式和深色模式。 283 284在WithTheme的作用范围内,组件的样式资源值会根据指定的模式,读取对应的深浅色模式系统和应用资源值。这意味着,在WithTheme作用范围内,组件的配色会根据所指定的深浅模式进行调整。 285 286如下面的示例所示,通过WithTheme({ colorMode: ThemeColorMode.DARK }),可以将作用范围内的组件设置为深色模式。 287 288设置局部深浅色时,需要添加dark.json资源文件,深浅色模式才会生效。 289 290 291 292dark.json数据示例: 293 ```ts 294 { 295 "color": [ 296 { 297 "name": "start_window_background", 298 "value": "#FFFFFF" 299 } 300 ] 301 } 302 ``` 303 304 ```ts 305 @Entry 306 @Component 307 struct DisplayPage { 308 @State message: string = 'Hello World'; 309 @State colorMode: ThemeColorMode = ThemeColorMode.DARK; 310 311 build() { 312 WithTheme({ colorMode: this.colorMode }) { 313 Row() { 314 Column() { 315 Text(this.message) 316 .fontSize(50) 317 .fontWeight(FontWeight.Bold) 318 Button('Switch ColorMode').onClick(() => { 319 if (this.colorMode === ThemeColorMode.LIGHT) { 320 this.colorMode = ThemeColorMode.DARK; 321 } else if (this.colorMode === ThemeColorMode.DARK) { 322 this.colorMode = ThemeColorMode.LIGHT; 323 } 324 }) 325 } 326 .width('100%') 327 } 328 .backgroundColor($r('sys.color.background_primary')) 329 .height('100%') 330 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.END, SafeAreaEdge.BOTTOM, SafeAreaEdge.START]) 331 } 332 } 333 } 334 ``` 335 336 337 338## 系统缺省token色值 339 340| Token | 场景类别 | Light | | Dark | | 341|--------------------------------------------|-----| --- |-----------| ------- | -------------------------------------------- | 342| theme.colors.brand | 品牌色 |#ff0a59f7|  |#ff317af7|| 343| theme.colors.warning | 一级警示色 |#ffe84026|  |#ffd94838|| 344| theme.colors.alert | 二级警示色 |#ffed6f21|  |#ffdb6b42|| 345| theme.colors.confirm | 确认色 |#ff64bb5c|  |#ff5ba854|| 346| theme.colors.fontPrimary | 一级文本 | #e5000000 |  |#e5ffffff|| 347| theme.colors.fontSecondary | 二级文本 | #99000000 |  |#99ffffff|| 348| theme.colors.fontTertiary | 三级文本 | #66000000 |  |#66ffffff|| 349| theme.colors.fontFourth | 四级文本 | #33000000 |  |#33ffffff|| 350| theme.colors.fontEmphasize | 高亮文本 | #ff0a59f7 |  |#ff317af7|| 351| theme.colors.fontOnPrimary | 一级文本反色 | #ffffffff |  |#ff000000|| 352| theme.colors.fontOnSecondary | 二级文本反色 | #99ffffff |  |#99000000|| 353| theme.colors.fontOnTertiary | 三级文本反色 | #66ffffff |  |#66000000|| 354| theme.colors.fontOnFourth | 四级文本反色 | #33ffffff |  |#33000000|| 355| theme.colors.iconPrimary | 一级图标 | #e5000000 |  |#e5ffffff|| 356| theme.colors.iconSecondary | 二级图标 | #99000000 |  |#99ffffff|| 357| theme.colors.iconTertiary | 三级图标 | #66000000 |  |#66ffffff|| 358| theme.colors.iconFourth | 四级图标 | #33000000 |  |#33ffffff|| 359| theme.colors.iconEmphasize | 高亮图标 | #ff0a59f7 |  |#ff317af7|| 360| theme.colors.iconSubEmphasize | 高亮辅助图标 | #660a59f7 |  |#66317af7|| 361| theme.colors.iconOnPrimary | 一级图标反色 | #ffffffff |  |#ff000000|| 362| theme.colors.iconOnSecondary | 二级图标反色 | #99ffffff |  |#99000000|| 363| theme.colors.iconOnTertiary | 三级图标反色 | #66ffffff |  |#66000000|| 364| theme.colors.iconOnFourth | 四级图标反色 | #33ffffff |  |#33000000|| 365| theme.colors.backgroundPrimary | 一级背景(实色/不透明色) | #ffffffff |  |#ffe5e5e5|| 366| theme.colors.backgroundSecondary | 二级背景(实色/不透明色) | #fff1f3f5 |  |#ff191a1c|| 367| theme.colors.backgroundTertiary | 三级背景(实色/不透明色) | #ffe5e5ea |  |#ff202224|| 368| theme.colors.backgroundFourth | 四级背景(实色/不透明色) | #ffd1d1d6 |  |#ff2e3033|| 369| theme.colors.backgroundEmphasize | 高亮背景(实色/不透明色) | #ff0a59f7 |  |#ff317af7|| 370| theme.colors.compForegroundPrimary | 前背景 | #ff000000 |  | #ffe5e5e5 || 371| theme.colors.compBackgroundPrimary | 白色背景 | #ffffffff || #ffffffff || 372| theme.colors.compBackgroundPrimaryTran | 白色透明背景 | #ffffffff || #33ffffff || 373| theme.colors.compBackgroundPrimaryContrary | 常亮背景 | #ffffffff || #ffe5e5e5 || 374| theme.colors.compBackgroundGray | 灰色背景 | #fff1f3f5 || #ffe5e5ea || 375| theme.colors.compBackgroundSecondary | 二级背景 | #19000000 || #19ffffff || 376| theme.colors.compBackgroundTertiary | 三级背景 | #0c000000 || #0cffffff || 377| theme.colors.compBackgroundEmphasize | 高亮背景 | #ff0a59f7 || #ff317af7 || 378| theme.colors.compBackgroundNeutral | 黑色中性高亮背景 | #ff000000 || #ffffffff || 379| theme.colors.compEmphasizeSecondary | 20%高亮背景 | #330a59f7 || #33317af7 || 380| theme.colors.compEmphasizeTertiary | 10%高亮背景 | #190a59f7 || #19317af7 || 381| theme.colors.compDivider | 分割线颜色 | #33000000 || #33ffffff || 382| theme.colors.compCommonContrary | 通用反色 | #ffffffff || #ff000000 || 383| theme.colors.compBackgroundFocus | 获焦态背景色 | #fff1f3f5 || #ff000000 || 384| theme.colors.compFocusedPrimary | 获焦态一级反色 | #e5000000 || #e5ffffff || 385| theme.colors.compFocusedSecondary | 获焦态二级反色 | #99000000 || #99ffffff || 386| theme.colors.compFocusedTertiary | 获焦态三级反色 | #66000000 || #66ffffff || 387| theme.colors.interactiveHover | 通用悬停交互式颜色 | #0c000000 || #0cffffff || 388| theme.colors.interactivePressed | 通用按压交互式颜色 | #19000000 || #19ffffff || 389| theme.colors.interactiveFocus | 通用获焦交互式颜色 | #ff0a59f7 || #ff317af7 || 390| theme.colors.interactiveActive | 通用激活交互式颜色 | #ff0a59f7 || #ff317af7 || 391| theme.colors.interactiveSelect | 通用选择交互式颜色 | #33000000 || #33ffffff || 392| theme.colors.interactiveClick | 通用点击交互式颜色 | #19000000 || #19ffffff || 393