【经验分享】鸿蒙如何实现自定义 App 样式主题

431 阅读4分钟

【经验分享】鸿蒙如何实现自定义 App 样式主题

在移动应用开发中,样式主题的设计是提升用户体验的重要环节。一个灵活且美观的主题系统,不仅能让应用更具吸引力,还能满足用户的个性化需求。鸿蒙操作系统(HarmonyOS)作为国产操作系统的代表,提供了强大的 UI 开发能力,尤其是 ArkUI 框架和 ArkTS 语言,让开发者能够轻松实现自定义样式主题。

本文将详细介绍如何在鸿蒙开发中实现自定义 App 样式主题,涵盖从基础概念到具体实现的完整流程。无论你是鸿蒙开发的新手,还是有一定经验的前端开发者,都能从中获得实用的技术参考。


1. 什么是样式主题?

样式主题是指应用中统一的视觉风格,包括颜色、字体、间距等 UI 元素的定义。通过主题系统,开发者可以:

  • 统一管理 UI 样式:避免重复定义样式,提高代码可维护性。
  • 动态切换主题:支持白天/黑夜模式切换,或用户自定义主题。
  • 提升用户体验:通过个性化的视觉设计,增强用户对应用的认同感。

2. 实现自定义样式主题的步骤

  1. 定义样式类,方便定制多个样式(举个简单例子):

    export class BaseVar {
      private _RBackground = "#f7f8fa";
      private _RRed = "#ee0a24";
      private _RBlue = "#1989fa";
      private _ROrange = "#ff976a";
      private _RGreen = "#07c160";
    ​
      private _RPrimaryColor = this._RBlue;
      private _RSuccessColor = this._RGreen;
      private _RDangerColor = this._RRed;
      private _RWarningColor = this._ROrange;
    ​
      get RBackground() {
        return this._RBackground;
      }
      set RBackground(value: string) {
        this._RBackground = value;
      }
      setRBackground(value: string) {
        this._RBackground = value;
        return this;
      }
      get RRed() {
        return this._RRed;
      }
      set RRed(value: string) {
        this._RRed = value;
        this.setRDangerColor(value);
      }
      setRRed(value: string) {
        this._RRed = value;
        this.setRDangerColor(value);
        return this;
      }
      get RBlue() {
        return this._RBlue;
      }
      set RBlue(value: string) {
        this._RBlue = value;
        this.setRPrimaryColor(value);
      }
      setRBlue(value: string) {
        this._RBlue = value;
        this.setRPrimaryColor(value);
        return this;
      }
      get ROrange() {
        return this._ROrange;
      }
      set ROrange(value: string) {
        this._ROrange = value;
        this.setRWarningColor(value);
      }
      setROrange(value: string) {
        this._ROrange = value;
        this.setRWarningColor(value);
        return this;
      }
      get RGreen() {
        return this._RGreen;
      }
      set RGreen(value: string) {
        this._RGreen = value;
        this.setRSuccessColor(value);
      }
      setRGreen(value: string) {
        this._RGreen = value;
        this.setRSuccessColor(value);
        return this;
      }
    ​
      get RPrimaryColor() {
        return this._RPrimaryColor;
      }
      set RPrimaryColor(value: string) {
        this._RPrimaryColor = value;
      }
      setRPrimaryColor(value: string) {
        this._RPrimaryColor = value;
        return this;
      }
    ​
      get RSuccessColor() {
        return this._RSuccessColor;
      }
      set RSuccessColor(value: string) {
        this._RSuccessColor = value;
      }
      setRSuccessColor(value: string) {
        this._RSuccessColor = value;
        return this;
      }
      get RDangerColor() {
        return this._RDangerColor;
      }
      set RDangerColor(value: string) {
        this._RDangerColor = value;
      }
      setRDangerColor(value: string) {
        this._RDangerColor = value;
        return this;
      }
      get RWarningColor() {
        return this._RWarningColor;
      }
      set RWarningColor(value: string) {
        this._RWarningColor = value;
      }
      setRWarningColor(value: string) {
        this._RWarningColor = value;
        return this;
      }
    }
    
  2. 实例化样式类,生成主题样式数据(可通过内部方法链式设置其属性值):

    export const lightBaseVar = new BaseVar();
    export const darkBaseVar = new BaseVar()
      .setRBlue("#0000ff")
      .setRGreen("#00ff00");
    
  3. 封装一个主题类,并导出主题类的实例:

    import { BaseVar } from "./const/base";
    import { lightBaseVar, darkBaseVar } from "./init/base";
    export class Theme {
      themes: Map<string, BaseVar> = new Map();
      themeName: string = "";
    ​
      constructor(themes?: Map<string, BaseVar>, themeName?: string) {
        if (themes) this.themes = themes;
        if (themeName) this.themeName = themeName;
      }
    ​
      add(themeName: string, theme: BaseVar) {
        this.themes.set(themeName, theme);
        return this;
      }
      set(themeName: string) {
        this.themeName = themeName;
        return this;
      }
      get() {
        return this.themes.get(this.themeName);
      }
    ​
      keys() {
        return this.themes.keys();
      }
      has(themeName: string) {
        return this.themes.has(themeName);
      }
      del(themeName: string) {
        if (this.has(themeName)) {
          this.themes.delete(themeName);
        }
        return this;
      }
    }
    ​
    export const theme = new Theme()
      .add("light", lightBaseVar)
      .add("dark", darkBaseVar)
      .set("light");
    

    至此,主题的就封装完毕。那么该如何使用呢?


3. 如何使用自定义主题

首先使用的时候,需要导入上面的theme ,然后如果需要修改主题直接调用set方法,如果需要新增主题,只需要实例化BaseVar类手动设置内部变量的值(可通过set方法修改 或 set[属性名]方法链式调用进行修改),再通过add 方法新增即可。下面举个组件使用的例子:

  1. 定义一个RConfigProvider组件。

    import {theme} from '../../theme/index'
    import {BaseVar} from '../../theme/const/base'
    export class RConfigProviderModifier implements AttributeModifier<ColumnAttribute>{
      private backgroundColor:string=''
      private height:string|number = '100%'
      private width:string|number='100%'
      private useTheme:BaseVar|undefined = theme.get()
    ​
      setBackgroundColor(backgroundColor:string):RConfigProviderModifier{
        this.backgroundColor = backgroundColor
        return this
      }
      setHeight(height:string|number):RConfigProviderModifier{
        this.height = height
        return this
      }
      setWidth(width:string|number):RConfigProviderModifier{
        this.width = width
        return this
      }
      setTheme(useTheme:BaseVar|undefined):RConfigProviderModifier{
        this.useTheme = useTheme
        return this
      }
    ​
      applyNormalAttribute(instance: ColumnAttribute): void {
        if(this.backgroundColor!=null){
          instance.backgroundColor(this.backgroundColor)
        }else if(this.useTheme!=undefined){
          instance.backgroundColor(this.useTheme.RBackground)
        }
        instance.width(this.width)
        instance.height(this.height)
      }
    }
    @Component
    export struct RConfigProvider{
      @Prop modifier: RConfigProviderModifier | null  = null;
      @Builder customBuilder() {};
      @BuilderParam customBuilderParam: () => void = this.customBuilder;
      @Prop @Watch("onThemeChange") themeName:string = 'light'
      @State isRender:number = 0
      aboutToAppear(){
        if(!this.modifier){
          this.modifier = new RConfigProviderModifier()
          theme.set(this.themeName)
          this.modifier.setTheme(theme.get())
        }
      }
      onThemeChange(){
        this.isRender = this.isRender+1
        theme.set(this.themeName)
        if(this.modifier!=null){
          this.modifier.setTheme(theme.get())
        }
    ​
      }
      build() {
        Column() {
          if(this.isRender % 2){
            this.customBuilderParam()
          }else{
            this.customBuilderParam()
          }
        }
        .attributeModifier(this.modifier)
      }
    }
    ​
    

    其核心就是外层维护使用的主题themeName ,当其变化后,重新渲染内部组件(已更新使用了的主题样式的组件,内部组件应在创建时使用theme.get()获取最新主题)

  2. 使用RConfigProvider组件

    import {theme} from '../../theme/index'
    @Entry
    @Component
    struct Index{
      @State themeName: string = 'light';
    ​
      @Builder customContentBuilder(){
       //此处放置使用了theme主题的样式的组件
      }
      
      build() {
        Column() {
           RConfigProvider(
             {
               themeName: this.themeName,
               customBuilderParam:this.componentBuilder
             }
           )
        }
        .height('100%')
        .width('100%')
      }
    }
    

    可在这个页面修改themeName值,组件内会自动同步重新渲染内部,达成组件样式切换。

4. 实践建议

  • 统一管理主题变量:将主题变量集中管理,便于维护和扩展。
  • 支持用户自定义主题:允许用户选择或自定义主题,提升用户体验。
  • 优化性能:避免频繁切换主题导致的性能问题,合理使用状态管理。

5. 总结

通过鸿蒙的 ArkUI 框架和 ArkTS 语言,开发者可以轻松实现自定义 App 样式主题。使用主题样式,都能为应用增添更多的灵活性和个性化。

这是题主使用的一种自定义主题样式的方案,更多可参考完整示例

希望这个封装思路能够帮助到大家,也可以动动小手指,给作者点个小星星~