鸿蒙开发 - 支持导出,跨文件使用的自定义样式 AttributeModifier

我们在自定义组件的时候,无论是用 @Styles 还是 @Extend,都很难真正做到独立的封装样式,因为这两者都不支持导出,不可以跨文件调用

这篇文章主要介绍一个接口 AttributeModifier,它很好的解决了这些弊端,可以实现样式的集中管理和复用,支持跨文件调用封装好的样式类

AttributeModifier

使用介绍

AttributeModifier 是一个接口,我们需要实现其中的一个方法 apply<状态名称>Attribute,来实现不同的场景

状态名称分为:默认态(Normal)、按压态(Pressed)、焦点态(Focused)、禁用态(Disabled)、选择态(Selected)

如果想设置元素的默认样式,就是 applyNormalAttribute,如果想设置元素的按压场景下的样式,就是 applyPressedAttribute

typescript 复制代码
declare interface AttributeModifier<T> {

  applyNormalAttribute?(instance: T): void;
  
  applyPressedAttribute?(instance: T): void;
  
  applyFocusedAttribute?(instance: T): void;
  
  applyDisabledAttribute?(instance: T): void;
  
  applySelectedAttribute?(instance: T): void;

}

举例

文字描述比较抽象,下面举例代码来讲解:

  • 我们可以新建个目录modifier,新建个文件index.ets,封装一个作用于 Button 组件的样式类,给它添加一些样式,如下:
typescript 复制代码
export class ButtonModifier implements AttributeModifier<ButtonAttribute> {
  applyNormalAttribute(instance: ButtonAttribute): void {
    instance
      .width(150)
      .height(50)
      .fontSize(20)
      .backgroundColor(Color.Orange)
  }
}
  1. 第一步:用 AttributeModifier 接口定义了一个 ButtonModifier 样式类
  2. 第二步:再实现 applyNormalAttribute 设置默认态样式:包括宽度、高度、字体等
  • 在组件文件中使用
typescript 复制代码
import { ButtonModifier } from './modifier/index'

@Entry
@Component
struct Index {
  @State buttonModifier: ButtonModifier = new ButtonModifier()

  build() {
    Column() {
      Button('按钮')
        .attributeModifier(this.buttonModifier)
    }
    .width('100%')
  }
}

效果如下:

这样我们就实现了一个对 Button 组件的样式封装,并且支持导出,跨文件使用

支持同时设置多个场景的样式

上面给 Button 组件增加了"默认态"的样式,可以在这基础上继续增加"按压态"的样式,就是按钮按下时的样式,如下:

  • 按钮按下的时候:增加边框,边框颜色等
typescript 复制代码
export class ButtonModifier2 implements AttributeModifier<ButtonAttribute> {
  applyNormalAttribute(instance: ButtonAttribute): void {
    instance
      .width(150)
      .height(80)
      .fontSize(20)
      .backgroundColor(Color.Orange)
  }

  applyPressedAttribute(instance: ButtonAttribute): void {
    instance
      .borderWidth(5)
      .borderColor(Color.Blue)
      .borderStyle(BorderStyle.Solid)
      .backgroundColor('#17A98D')
  }
}
  • 在组件中引用
typescript 复制代码
import { ButtonModifier2 } from './modifier/index'

@Entry
@Component
struct Index {
  @State buttonModifier: ButtonModifier2 = new ButtonModifier2()

  build() {
    Column() {
      Button('按钮')
        .attributeModifier(this.buttonModifier)
    }
    .width('100%')
  }
}

效果如下:

接口中支持传参和业务逻辑

ButtonModifier3 样式类中,定义一个 isClick 变量,来区分按钮是否点击过,然后分别对点击和没有点击的情况下增加样式,如下:

typescript 复制代码
export class ButtonModifier3 implements AttributeModifier<ButtonAttribute> {
  isClick: boolean = false

  constructor(flag?: boolean) {
    this.isClick = !!flag
  }

  applyNormalAttribute(instance: ButtonAttribute): void {
    if (this.isClick) {
      instance.backgroundColor('#707070')
    } else {
      instance
        .borderColor('#707070')
        .borderWidth(2)
        .backgroundColor('#17A98D')
    }
  }
}
  • 在组件中调用
typescript 复制代码
import { ButtonModifier3 } from './modifier/index'

@Entry
@Component
struct Index {
  @State buttonModifier: ButtonModifier3 = new ButtonModifier3()
  // @State buttonModifier: ButtonModifier3 = new ButtonModifier3(true)
  
  build() {
    Column() {
      Button('按钮')
        .attributeModifier(this.buttonModifier)
        .onClick(() => {
          this.buttonModifier.isClick = !this.buttonModifier.isClick
        })
    }
    .width('100%')
  }
} 

效果如下:

总结

  • 注意事项

我们在实现 AttributeModifier<T> 接口的实例,T 必须指定为组件对应的 Attribute类型,或者是CommonAttribute,如下:

typescript 复制代码
// 作用于 Button 组件,就要传入 ButtonAttribute
export class Modifier1 implements AttributeModifier<ButtonAttribute> {
 applyNormalAttribute?(instance: ButtonAttribute): void;
}

// 作用于 TextInput 组件,就要传入 TextInputAttribute
export class Modifier2 implements AttributeModifier<TextInputAttribute> {
 applyNormalAttribute?(instance: ButtonAttribute): void;
}
  • @Style 和 @Extend 和 AttributeModifier 三者对比
能力 @Styles @Extend AttributeModifier
跨文件导出 不支持 不支持 支持
通用属性设置 支持 支持 支持
通用事件设置 支持 支持 部分支持
组件特有属性设置 不支持 支持 部分支持
组件特有事件设置 不支持 支持 部分支持
参数传递 不支持 支持 支持
多态样式 支持 不支持 支持
业务逻辑 不支持 不支持 支持

最后

如果大家有不理解的地方可以留言,或自行阅读文档 文档地址

相关推荐
伶俜668 小时前
鸿蒙原生应用实战(十九)ArkUI 喝水提醒 App:定时通知 + 每日记录 + 统计图表
华为·harmonyos
风华圆舞9 小时前
Flutter + 鸿蒙 Intents Kit:页面直达能力的完整接入方案
flutter·ui·华为·harmonyos
三声三视9 小时前
Electron 在鸿蒙 PC 上跑 webview,我是怎么把首屏从 4.2s 干到 1.1s 的
华为·electron·harmonyos·鸿蒙
互联网散修10 小时前
鸿蒙实战:从0到1构建功能完备的搜索页面
华为·harmonyos
花椒技术10 小时前
RN 多包热更新实践:更新校验、运行时加载与 Bridge 缓存治理
react native·react.js·harmonyos
不喝水就会渴11 小时前
【共创季稿事节】HarmonyOS 7.0 时代的新基建 :DevEco CLI + Claude Code,鸿蒙 AI 开发的黄金搭档
人工智能·华为·harmonyos
星释11 小时前
鸿蒙智能体开发实战:2.创建单Agent
harmonyos·智能体
世人万千丶11 小时前
成语接龙小应用 - HarmonyOS ArkUI 开发实战-TextInput与List列表-PC版本
华为·list·harmonyos·鸿蒙·鸿蒙系统
TrisighT11 小时前
AI写鸿蒙UI:10个跑崩8个,剩下2个看运气
ai编程·harmonyos·arkts
伶俜6612 小时前
鸿蒙原生应用实战(十八)ArkUI 记账本:SQLite 账单 + 图表统计 + 分类管理
jvm·sqlite·harmonyos