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

最后

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

相关推荐
Swift社区2 小时前
鸿蒙游戏里的 AI Agent 设计
人工智能·游戏·harmonyos
亚历克斯神2 小时前
Flutter 组件 t_stats 的适配 鸿蒙Harmony 实战 - 驾驭高性能统计学运算、实现鸿蒙端海量数据实时态势感知与工业级描述性统计方案
flutter·harmonyos·鸿蒙·openharmony·t_stats
键盘鼓手苏苏2 小时前
Flutter 组件 angel3_orm_mysql 的适配 鸿蒙Harmony 实战 - 驾驭专业 ORM 映射引擎、实现鸿蒙端与 MySQL 数据库的透明映射与高性能 SQL 审计方案
flutter·harmonyos·鸿蒙·openharmony·angel3_orm_mysql
左手厨刀右手茼蒿2 小时前
Flutter 组件 serverpod_swagger 的适配 鸿蒙Harmony 实战 - 驾驭 API 文档自动化、实现鸿蒙端全栈联调与 Swagger UI 动态审计方案
flutter·harmonyos·鸿蒙·openharmony·serverpod_swagger
钛态2 小时前
Flutter 三方库 discord_interactions 的鸿蒙化适配指南 - 在 OpenHarmony 打造高效的社交机器人交互底座
flutter·harmonyos·鸿蒙·openharmony·discord_interactions
加农炮手Jinx2 小时前
Flutter 组件 dascade 的适配 鸿蒙Harmony 实战 - 驾驭级联式异步数据流、实现鸿蒙端响应式 UI 状态泵与复杂业务逻辑解耦方案
flutter·harmonyos·鸿蒙·openharmony
国医中兴2 小时前
Flutter 组件 r_flutter 的适配 鸿蒙Harmony 实战 - 驾驭资源映射自动化、实现鸿蒙端资产强类型引用与资产冲突静态校验方案
flutter·r语言·harmonyos
里欧跑得慢2 小时前
Flutter 组件 postgres_crdt 的适配 鸿蒙Harmony 实战 - 驾驭分布式无冲突复制数据类型、实现鸿蒙端高性能离线对等同步架构方案
flutter·harmonyos·鸿蒙·openharmony·postgres_crdt
王码码20352 小时前
Flutter for OpenHarmony:使用 pluto_grid 打造高性能数据网格
flutter·http·华为·架构·harmonyos
王码码20352 小时前
Flutter 组件 d_method 适配 鸿蒙Harmony 实战 - 驾驭核心极地盲区开发终端调试网络、构建极简跨层穿透护级大日志脱机雷达防线
flutter·harmonyos·鸿蒙·openharmony·d_method