(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,还请三连支持一波哇ヾ(@^∇^@)ノ)
目录
自定义扩展能力概述
ArkUI框架提供一系列基于Modifier的自定义扩展能力,通过与UI分离的方式,对已有UI组件的属性、手势、内容进行扩展修改。包括AttributeModifier、GestureModifier、DrawModifier等。其中AttributeModifier和AttributeUpdater允许开发者通过自定义类设置属性,扩展了属性设置的实现方式,能够与原生属性设置方式混合使用。
AttributeModifier
声明式语法引入的@Styles和@Extend两个装饰器,虽然可以解决部分复用的问题,但是使用场景十分受限。为此,ArkUI引入了AttributeModifier的机制,可以通过Modifier对象动态修改属性。与@Styles和@Extend相比,AttributeModifier的能力和灵活性更好。当前持续在构建全量的属性、事件设置能力,推荐使用。
AttributeUpdater
AttributeUpdater是一个特殊的AttributeModifier,除了继承AttributeModifier的能力,还提供了获取属性对象的能力。通过属性对象可以不经过状态变量,直接更新对应属性。开发者可以通过AttributeUpdater实现自定义的更新策略,进一步提高属性更新的性能。
AttributeModifier
概述
声明式语法引入了@Styles和@Extend两个装饰器,可以解决部分复用的问题,但是存在以下受限场景:
- @Styles和@Extend均是编译期处理,不支持跨文件的导出复用。
- @Styles仅能支持通用属性、事件,不支持组件特有的属性。
- @Styles虽然支持在多态样式下使用,但不支持传参,无法对外开放一些属性。
- @Extend虽然能支持特定组件的私有属性、事件,但同样不支持跨文件导出复用。
- @Styles、@Extend对于属性设置,无法支持业务逻辑编写,动态决定是否设置某些属性。只能通过三元表达式对所有可能设置的属性进行全量设置,设置大量属性时效率低下。
为了解决上述问题,ArkUI引入了AttributeModifier的机制,可以通过Modifier对象动态修改属性。能力对比如下:
能力 @Styles @Extend AttributeModifier 跨文件导出 不支持 不支持 支持 通用属性设置 支持 支持 支持 通用事件设置 支持 支持 部分支持 组件特有属性设置 不支持 支持 部分支持 组件特有事件设置 不支持 支持 部分支持 参数传递 不支持 支持 支持 多态样式 支持 不支持 支持 业务逻辑 不支持 不支持 支持 可以看出,AttributeModifier的能力和灵活性更好,当前持续在构建全量的属性、事件设置能力。未来,AttributeModifier可以替代@Styles和@Extend几乎所有的能力,建议上述场景都使用AttributeModifier。
接口定义
declare interface AttributeModifier<T> {
applyNormalAttribute?(instance: T): void;
applyPressedAttribute?(instance: T): void;
applyFocusedAttribute?(instance: T): void;
applyDisabledAttribute?(instance: T): void;
applySelectedAttribute?(instance: T): void;
}
AttributeModifier是一个接口,需要开发者实现ApplyXxxAttribute的方法。Xxx表示多态的场景,支持默认态、按压态、焦点态、禁用态、选择态。其中,T是组件的属性类型,开发者可以在回调中获取到属性对象,通过该对象设置属性。
declare class CommonMethod<T> {
attributeModifier(modifier: AttributeModifier<T>): T;
}
在组件的通用方法上,增加了attributeModifier传入自定义的Modifier。由于组件在实例化时会明确T的类型,所以调用该方法时,T必须是组件对应的Attribute类型,或者是CommonAttribute。
行为规格
- 组件通用方法attributeModifier支持传入一个实现AttributeModifier<T>接口的实例,T必须是组件对应的Attribute类型,或者是CommonAttribute。
- 在组件首次初始化或者关联的状态变量发生变化时,如果传入的实例实现了对应接口,会触发applyNormalAttribute。
- 回调applyNormalAttribute时,会传入组件属性对象,通过该对象可以设置当前组件的属性/事件。
- 暂未支持的属性/事件,执行时会抛异常。
- 属性变化触发ApplyXxxAttribute函数时,该组件之前已设置的属性,在本次变化后未设置的属性会恢复为属性的默认值。
- 可以通过该接口使用多态样式的功能,例如如果需要在组件进入按压态时设置某些属性,就可以通过自定义实现applyPressedAttribute方法完成。
- 一个组件上同时使用属性方法和applyNormalAttribute设置相同的属性,遵循属性覆盖原则,即后设置的属性生效。
- 一个Modifier实例对象可以在多个组件上使用。
- 一个组件上多次使用applyNormalAttribute设置不同的Modifier实例,每次状态变量刷新均会按顺序执行这些实例的方法属性设置,同样遵循属性覆盖原则。
属性设置与修改
AttributeModifier可以分离UI与样式,支持参数传递及业务逻辑编写,并且通过状态变量触发刷新。
// button_modifier.ets
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
// 可以实现一个Modifier,定义私有的成员变量,外部可动态修改
isDark: boolean = false
// 通过构造函数,创建时传参
constructor(dark?: boolean) {
this.isDark = dark ? dark : false
}
applyNormalAttribute(instance: ButtonAttribute): void {
// instance为Button的属性对象,可以通过instance对象对属性进行修改
if (this.isDark) { // 支持业务逻辑的编写
// 属性变化触发apply函数时,变化前已设置并且变化后未设置的属性会恢复为默认值
instance.backgroundColor(Color.Black)
} else {
// 支持属性的链式调用
instance.backgroundColor(Color.Red)
.borderColor(Color.Black)
.borderWidth(2)
}
}
}
// demo.ets
import { MyButtonModifier } from './button_modifier'
@Entry
@Component
struct attributeDemo {
// 支持用状态装饰器修饰,行为和普通的对象一致
@State modifier: MyButtonModifier = new MyButtonModifier(true);
build() {
Row() {
Column() {
Button("Button")
.attributeModifier(this.modifier)
.onClick(() => {
// 对象的一层属性被修改时,会触发UI刷新,重新执行applyNormalAttribute
this.modifier.isDark = !this.modifier.isDark
})
}
.width('100%')
}
.height('100%')
}
}
一个组件上同时使用属性方法和applyNormalAttribute设置相同的属性,遵循属性覆盖原则,即后设置的属性生效。
// button_modifier.ets
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
isDark: boolean = false
constructor(dark?: boolean) {
this.isDark = dark ? dark : false
}
applyNormalAttribute(instance: ButtonAttribute): void {
if (this.isDark) {
instance.backgroundColor(Color.Black)
} else {
instance.backgroundColor(Color.Red)
.borderColor(Color.Black)
.borderWidth(2)
}
}
}
// demo.ets
import { MyButtonModifier } from './button_modifier';
@Entry
@Component
struct attributeDemo {
@State modifier: MyButtonModifier = new MyButtonModifier(true);
build() {
Row() {
Column() {
// 先设置属性,后设置modifier,按钮颜色会跟随modifier的值改变
Button("Button")
.backgroundColor(Color.Blue)
.attributeModifier(this.modifier)
.onClick(() => {
this.modifier.isDark = !this.modifier.isDark
})
}
.width('100%')
}
.height('100%')
}
}
一个组件上多次使用applyNormalAttribute设置不同的Modifier实例,每次状态变量刷新均会按顺序执行这些实例的方法属性设置,遵循属性覆盖原则,即后设置的属性生效。
// button_modifier.ets
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
isDark: boolean = false
constructor(dark?: boolean) {
this.isDark = dark ? dark : false
}
applyNormalAttribute(instance: ButtonAttribute): void {
if (this.isDark) {
instance.backgroundColor(Color.Black)
.width(200)
} else {
instance.backgroundColor(Color.Red)
.width(100)
}
}
}
// button_modifier2.ets
export class MyButtonModifier2 implements AttributeModifier<ButtonAttribute> {
isDark2: boolean = false
constructor(dark?: boolean) {
this.isDark2 = dark ? dark : false
}
applyNormalAttribute(instance: ButtonAttribute): void {
if (this.isDark2) {
instance.backgroundColor('#2787D9')
} else {
instance.backgroundColor('#707070')
}
}
}
// demo.ets
import { MyButtonModifier } from './button_modifier';
import { MyButtonModifier2 } from './button_modifier2';
@Entry
@Component
struct attributeDemo {
@State modifier: MyButtonModifier = new MyButtonModifier(true);
@State modifier2: MyButtonModifier2 = new MyButtonModifier2(true);
build() {
Row() {
Column() {
Button("Button")
.attributeModifier(this.modifier)
.attributeModifier(this.modifier2)
.onClick(() => {
this.modifier.isDark = !this.modifier.isDark
this.modifier2.isDark2 = !this.modifier2.isDark2
})
}
.width('100%')
}
.height('100%')
}
}
设置多态样式、事件
使用AttributeModifier设置多态样式、事件,实现事件逻辑的复用,支持默认态、按压态、焦点态、禁用态、选择态。例如如果需要在组件进入按压态时设置某些属性,就可以通过自定义实现applyPressedAttribute方法完成。
// button_modifier.ets
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
applyNormalAttribute(instance: ButtonAttribute): void {
// instance为Button的属性对象,设置正常状态下属性值
instance.backgroundColor(Color.Red)
.borderColor(Color.Black)
.borderWidth(2)
}
applyPressedAttribute(instance: ButtonAttribute): void {
// instance为Button的属性对象,设置按压状态下属性值
instance.backgroundColor(Color.Green)
.borderColor(Color.Orange)
.borderWidth(5)
}
}
// demo.ets
import { MyButtonModifier } from './button_modifier'
@Entry
@Component
struct attributeDemo {
@State modifier: MyButtonModifier = new MyButtonModifier();
build() {
Row() {
Column() {
Button("Button")
.attributeModifier(this.modifier)
}
.width('100%')
}
.height('100%')
}
}
AttributeUpdater
概述
大量属性频繁更新时,如果使用状态变量,会导致前端状态管理计算量太大,并需要对单个组件进行全量的属性更新。虽然可以通过AttributeModifier的机制按需更新,但是前端还是默认会有一些diff和reset的策略。
为此引入了AttributeUpdater的能力,它是一个特殊的AttributeModifier,除了继承AttributeModifier的能力,还提供了获取属性对象的能力。通过属性对象可以不经过状态变量,直接更新对应属性。使用AttributeUpdater,开发者可实现自定义的更新策略,进一步提高属性更新的性能。但是由于该能力比较灵活,无法限制“单一数据源”的规则,同时和状态变量更新相同属性时,存在相互覆盖的情况,需要开发者自己保障属性设置的合理性。
接口定义
export declare class AttributeUpdater<T, C = Initializer<T>> implements AttributeModifier<T> {
applyNormalAttribute?(instance: T): void;
initializeModifier(instance: T): void;
get attribute(): T | undefined;
updateConstructorParams: C;
}
AttributeUpdater实现了AttributeModifier接口,额外提供了initializeModifier,可以对组件的属性进行初始化,并且通过attribute属性方法,获取到属性对象,通过该对象直接更新对应组件的属性。另外也可以直接通过updateConstructorParams更新组件的构造参数。
行为规格
- 开发者可以实现一个AttributeUpdater<T>的类,并通过组件的AttributeModifier设置,首次绑定时会触发initializeModifier方法,进行属性的初始化,后续其它的生命周期和AttributeModifier保持一致。
- 组件初始化完成之后,可以通过AttributeUpdater实例的attribute属性方法,获取到属性对象,否则为undefined。
- 通过attribute属性对象直接修改属性,会将最新设置的属性记录在当前对象中,并立即触发组件属性的更新。
- 如果将AttributeUpdater实例标记为状态变量进行修改,或者通过其它状态变量更新对应组件的属性,会触发applyNormalAttribute的流程,如果开发者没有覆写该逻辑,默认会将属性对象记录的所有属性,批量进行一次更新。
- 如果开发者复写applyNormalAttribute的逻辑,并且不调用super的该方法,将会失去获取attribute属性对象的能力,不会调用initializeModifier方法。
- 一个AttributeUpdater对象只能同时关联一个组件,否则只会有一个组件生效属性设置。
通过modifier直接修改属性
组件初始化完成之后,可以通过AttributeUpdater实例的attribute属性方法,获取到属性对象,通过属性对象直接修改属性,会立即触发组件属性的更新。
import { AttributeUpdater } from '@ohos.arkui.modifier'
class MyButtonModifier extends AttributeUpdater<ButtonAttribute> {
initializeModifier(instance: ButtonAttribute): void {
instance.backgroundColor('#2787D9')
.width('50%')
.height(30)
}
}
@Entry
@Component
struct updaterDemo {
modifier: MyButtonModifier = new MyButtonModifier()
build() {
Row() {
Column() {
Button("Button")
.attributeModifier(this.modifier)
.onClick(() => {
this.modifier.attribute?.backgroundColor('#17A98D').width('30%')
})
}
.width('100%')
}
.height('100%')
}
}
通过modifier更新组件的构造参数
可以直接通过AttributeUpdater实例的updateConstructorParams方法,更新组件的构造参数。
import { AttributeUpdater } from '@ohos.arkui.modifier'
class MyTextModifier extends AttributeUpdater<TextAttribute, TextInterface> {
initializeModifier(instance: TextAttribute): void {
}
}
@Entry
@Component
struct updaterDemo {
modifier: MyTextModifier = new MyTextModifier()
build() {
Row() {
Column() {
Text("Text")
.attributeModifier(this.modifier)
.fontColor(Color.White)
.fontSize(14)
.border({ width: 1 })
.textAlign(TextAlign.Center)
.lineHeight(20)
.width(200)
.height(50)
.backgroundColor('#2787D9')
.onClick(() => {
this.modifier.updateConstructorParams('Update');
})
}
.width('100%')
}
.height('100%')
}
}
【往届均已EI检索|连续3届EI检索】第四届电气工程与计算机技术国际学术会议(ICEECT 2024)_艾思科蓝_学术一站式服务平台
更多学术会议请看 学术会议-学术交流征稿-学术会议在线-艾思科蓝
标签:AttributeModifier,自定义,鸿蒙,instance,设置,组件,modifier,day18,属性 From: https://blog.csdn.net/weixin_73295475/article/details/142062659