Harmonyos-属性修改器和更新器

[复制链接]
发表于 2025-9-17 19:23:07 | 显示全部楼层 |阅读模式
概述

ArkUI框架提供一系列基于Modifier的自界说扩展能力,通过与UI分离的方式,对已有UI组件的属性、手势、内容举行扩展修改,以满意开发者在不改变UI组件底层实现的环境下,快速调解UI组件表面、活动等需求。
属性修改器 (AttributeModifier)

概述

声明式语法引入了@Styles和@Extend两个装饰器,可以办理复用雷同自界说样式的题目,但是存在以下受限场景:


  • @Styles和@Extend均是编译期处理,不支持跨文件的导出复用。
  • @Styles仅能支持通用属性、变乱,不支持组件特有的属性。
  • @Styles固然支持在多态样式下使用,但不支持传参,无法对外开放一些属性。
  • @Extend固然能支持特定组件的私有属性、变乱,但同样不支持跨文件导出复用。
  • @Styles、@Extend对于属性设置,无法支持业务逻辑编写,动态决定是否设置某些属性,只能通过三元表达式对全部大概设置的属性举行全量设置,设置大量属性时服从较低。
为了办理上述题目,ArkUI引入了AttributeModifier机制,可以通过Modifier对象动态修改属性。能力对好比下:

可以看出,与@Styles和@Extend相比,AttributeModifier提供了更强的能力和机动性,且在连续完满全量的属性和变乱设置能力,因此保举优先使用AttributeModifier。
接口界说

  1. declare interface AttributeModifier<T> {
  2.   applyNormalAttribute?(instance: T): void;
  3.   
  4.   applyPressedAttribute?(instance: T): void;
  5.   
  6.   applyFocusedAttribute?(instance: T): void;
  7.   
  8.   applyDisabledAttribute?(instance: T): void;
  9.   
  10.   applySelectedAttribute?(instance: T): void;
  11. }
复制代码
AttributeModifer是一个接口,开发者必要实现此中applyXxxAttribute方法, 来实现对应场景的属性设置。
Xxx体现多态的场景,支持默认态(Normal)、按压态(Pressed)、焦点态(Focused)、禁用态(Disabled)、选择态(Selected)。T是组件的属性范例,开发者可以在回调中获取到属性对象,通过该对象设置属性
  1. declare class CommonMethod<T> {
  2.   attributeModifier(modifier: AttributeModifier<T>): T;
  3. }
复制代码
组件的通用方法增加了attributeModifier方法,支持传入自界说的Modifier。由于组件在实例化时会明白T的范例,以是调用该方法时,T必须指定为组件对应的Attribute范例,大概是CommonAttribute。
使用阐明



  • 组件通用方法attributeModifier支持传入一个实现AttributeModifier接口的实例,T必须指定为组件对应的Attribute范例,大概是CommonAttribute。
  • 在组件初次初始化大概关联的状态变量发生变革时,如果传入的实例实现了对应接口,会触发applyNormalAttribute。
  • 回调applyNormalAttribute时,会传入组件属性对象,通过该对象可以设置当前组件的属性/变乱。
  • 暂未支持的属性/变乱,执行时会抛非常。
  • 属性变革触发applyXxxAttribute函数时,该组件之前已设置的属性,在本次变革后未设置的属性会规复为属性的默认值。
  • 可以通过该接口使用多态样式的功能,比方如果必要在组件进入按压态时设置某些属性,就可以通过自界说实现applyPressedAttribute方法完成。
  • 一个组件上同时使用属性方法和applyNormalAttribute设置雷同的属性,依照属性覆盖原则,即后设置的属性收效。
  • 一个Modifier实例对象可以在多个组件上使用。
  • 一个组件上多次使用applyNormalAttribute设置不同的Modifier实例,每次状态变量革新均会按序次执行这些实例的方法属性设置,同样依照属性覆盖原则。
设置和修改组件属性

AttributeModifier可以分离UI与样式,支持参数通报及业务逻辑编写,并且通过状态变量触发革新。
下面以Text组件的一些属性为示例:
SkinManager.ets的代码
  1. @Observed
  2. export class SkinManager {
  3.   // 是否黑板
  4.   isDrak: boolean = false
  5.   // 是否使用大字体
  6.   isLargeFont: boolean = false
  7. }
复制代码
SkinTextAttributeModifier.ets代码:
  1. import { SkinManager } from "./SkinManage";
  2. export class SkinTextAttributeModifier implements AttributeModifier<TextAttribute> {
  3.   private skinManger: SkinManager
  4.   private _fontSize?: number = 20
  5.   private _fontColor?: ResourceColor = Color.Black
  6.   private _backgroundColor?: ResourceColor = Color.Orange
  7.   constructor(skinManage: SkinManager) {
  8.     this.skinManger = skinManage
  9.   }
  10.   fontSize(fontSize?: number): SkinTextAttributeModifier {
  11.     this._fontSize = fontSize
  12.     return this
  13.   }
  14.   fontColor(fontColor?: ResourceColor): SkinTextAttributeModifier {
  15.     this._fontColor = fontColor
  16.     return this
  17.   }
  18.   backgroundColor(backgroundColor?: ResourceColor): SkinTextAttributeModifier {
  19.     this._backgroundColor = backgroundColor
  20.     return this
  21.   }
  22.   applyNormalAttribute(instance: TextAttribute): void {
  23.     // 这里可以进项皮肤的更换逻辑, 示例中是一个简单的例子
  24.     if (this._fontColor) {
  25.       // 这里传参应该传递现在的设置颜色, 然后或去对应皮肤的对应的颜色
  26.       instance.fontColor(this.getColor(this.skinManger.isDrak))
  27.     }
  28.     if (this._fontSize) {
  29.       // 这里传参应该传递现在设置的字体大小, 然后或去计算对应字体大小在重新设置
  30.       instance.fontSize(this.getSize(this.skinManger.isLargeFont))
  31.     }
  32.     if (this._backgroundColor) {
  33.       instance.backgroundColor(this._backgroundColor)
  34.     }
  35.   }
  36.   getColor(isDark: boolean) {
  37.     return isDark ? Color.White : Color.Black
  38.   }
  39.   getSize(isLarge: boolean) {
  40.     return isLarge ? 40 : 20
  41.   }
  42. }
复制代码
demo示例代码:
  1. import { SkinManager } from './SkinManage';
  2. import { SkinTextAttributeModifier } from './SkinTextAttributeModifier';
  3. @Entry
  4. @Component
  5. struct Index {
  6.   @State message: string = 'Hello World';
  7.   @State skinManager: SkinManager = new SkinManager()
  8.   build() {
  9.     Column() {
  10.       Text(this.message)
  11.         .fontWeight(FontWeight.Bold)
  12.         // 通过属性修改器来设置属性
  13.         .attributeModifier(new SkinTextAttributeModifier(this.skinManager).fontSize(20)
  14.           .fontColor(Color.White)
  15.           .backgroundColor(Color.Gray))
  16.       Button("换肤").onClick((event: ClickEvent) => {
  17.         this.skinManager.isDrak = !this.skinManager.isDrak
  18.       })
  19.       Button("更改字体大小").onClick((event: ClickEvent) => {
  20.         this.skinManager.isLargeFont = !this.skinManager.isLargeFont
  21.       })
  22.     }
  23.     .height('100%')
  24.     .width('100%')
  25.   }
  26. }
复制代码
上述例子只是先容了下使用applyNormalAttribute方法, 如果你想设置更多状态的UI变革,你可以实现其他的接口。
属性更新器(AttributeModifier)

概述

在大量频繁更新的场景下,使用状态变量大概会导致前端状态管理的盘算量过大,并且必要对单个组件举行全量属性更新。只管可以通过AttributeModifier机制实现按需更新属性,但前端仍会接纳肯定的diff和reset战略,这大概带来性能题目。
AttributeUpdater作为一个特别的AttributeModifier,不但继续了AttributeModifier的功能,还提供了直接获取属性对象的能力。通过属性对象,开发者可以或许直接更新对应属性,无需经过状态变量。开发者可以使用AttributeUpdater实现自界说的更新战略,从而进一步提升属性更新的性能
由于AttributeUpdater提供了较高的机动性,无法限定“单一数据源”的规则,因此在与状态变量同时更新同一属性时,存在相互覆盖的环境。这要求开发者必须确保属性设置的公道性。
接口界说

  1. export declare class AttributeUpdater<T, C = Initializer<T>> implements AttributeModifier<T> {
  2.   applyNormalAttribute?(instance: T): void;
  3.   initializeModifier(instance: T): void;
  4.   get attribute(): T | undefined;
  5.   updateConstructorParams: C;
  6. }
复制代码
AttributeUpdater实现了AttributeModifier接口,并额外提供了initializeModifier,可以对组件的属性举行初始化。通过attribute属性方法可以获取属性对象,直接更新对应组件的属性。别的也可以直接通过updateConstructorParams更新组件的构造参数。
使用阐明



  • 开发者可以继续AttributeUpdater<T>类,并通过组件的通用方法attributeModifier设置,初次绑定时会触发initializeModifier方法,举行属性的初始化,后续别的的生命周期和AttributeModifier保持同等。
  • 组件初始化完成之后,开发者可以通过AttributeUpdater实例的attribute属性方法,获取到属性对象,若获取不到则为undefined。
  • 通过attribute属性对象直接修改属性,会将最新设置的属性记录在当前对象中,并立刻触发组件属性的更新。
  • 如果将AttributeUpdater实例标志为状态变量举行修改,大概通过别的状态变量更新对应组件的属性,会触发applyNormalAttribute的流程,如果开发者没有复写该逻辑,默认会将属性对象记录的全部属性,举行一次批量更新。
  • 如果开发者复写applyNormalAttribute的逻辑,并且不调用super的该方法,将会失去获取attribute属性对象的能力,不会调用initializeModifier方法。
  • 一个AttributeUpdater对象只能同时关联一个组件,否则只会有一个组件的属性设置收效。
通过modifier直接修改属性和更新构造参数

组件初始化完成之后,开发者可以通过AttributeUpdater实例的attribute属性方法,获取到属性对象。通过属性对象直接修改属性,会立刻触发组件属性的更新
SkinButtonModifier.ets:
  1. import { AttributeUpdater } from "@kit.ArkUI";
  2. export class SkinButtonModifier extends AttributeUpdater<ButtonAttribute, ButtonInterface> {
  3.   // 首次绑定时触发initializeModifier方法,进行属性初始化
  4.   initializeModifier(instance: ButtonAttribute): void {
  5.     instance.backgroundColor(Color.Orange)
  6.       .width('50%')
  7.       .height(30)
  8.   }
  9. }
复制代码
示例代码:
  1. import { SkinButtonModifier } from './SkinButtonModifier';
  2. @Entry
  3. @Component
  4. struct Index {
  5.   // 创建一个update修改器
  6.   private modifier: SkinButtonModifier = new SkinButtonModifier()
  7.   build() {
  8.     Column() {
  9.       Button('test attributeModifier')
  10.         .attributeModifier(this.modifier)
  11.         .onClick((event: ClickEvent) => {
  12.           // 通过attribute,直接修改组件属性,并立即触发组件属性更新
  13.           this.modifier.attribute?.backgroundColor(Color.Red).width('80%').height(44)
  14.           // 调用updateConstructorParams方法,直接更新组件的构造参数
  15.           this.modifier.updateConstructorParams('update Title')
  16.       })
  17.     }
  18.     .height('100%')
  19.     .width('100%')
  20.   }
  21. }
复制代码
修改前结果:

点击修改后的结果:

参考资料

官方文档:自界说扩展

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表