鸿蒙开发 - 支持导出,跨文件使用的自定义样式 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
跨文件导出 不支持 不支持 支持
通用属性设置 支持 支持 支持
通用事件设置 支持 支持 部分支持
组件特有属性设置 不支持 支持 部分支持
组件特有事件设置 不支持 支持 部分支持
参数传递 不支持 支持 支持
多态样式 支持 不支持 支持
业务逻辑 不支持 不支持 支持

最后

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

相关推荐
程序员黑豆8 小时前
鸿蒙应用开发:@Link 装饰器实现父子组件双向同步
前端·后端·harmonyos
2501_919749038 小时前
华为鸿蒙免费解压缩APP—小羊解压缩
华为·harmonyos
爱写代码的森8 小时前
鸿蒙三方库 | harmony-utils之EncryptUtil URL编解码详解
服务器·华为·harmonyos·鸿蒙·huawei
youtootech9 小时前
HarmonyOS 6.0 卡片式信息流与瀑布流布局
华为·harmonyos
luoyayun36111 小时前
【Qt for Harmony】 Qt 5.12.12 鸿蒙版 Windows 交叉编译
qt·harmonyos·qt for harmony
木木子2212 小时前
# 鸿蒙 HarmonyOS 应用开发实战(第25期)|骰子(Dice Roller)— Unicode 符号与动画渲染精讲
华为·harmonyos
qizayaoshuap13 小时前
# HarmonyOS ArkTS 记忆翻牌游戏深度解析 —— Fisher-Yates 洗牌与翻牌匹配机制
游戏·华为·harmonyos
youtootech13 小时前
HarmonyOS 6.0 自定义绘图表盘与仪表
华为·harmonyos
yaoyaoxingzhe1 天前
HarmonyOS应用《玄象》开发实战:Canvas 绘制星宿连线:moveTo / lineTo / stroke 路径绘制
harmonyos·鸿蒙
echohelloworld111 天前
HarmonyOS应用开发实战:猫猫大作战-springMotion 三参数、responsiveSpringMotion 响应式弹簧、与 EaseO
harmonyos·鸿蒙