1# 动态属性设置
2
3动态设置组件的属性,支持开发者在属性设置时使用if/else语法,且根据需要使用多态样式设置属性。
4
5>  **说明:**
6>
7>  从API Version 11开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
8>
9> 在attributeModifier中设置的属性尽量不要与其他方法设置的属性相同,避免在页面刷新时attributeModifier不生效。
10>
11> attributeModifier不支持自定义组件。
12
13## attributeModifier
14
15attributeModifier(modifier:&nbsp;AttributeModifier\<T>)
16
17动态设置组件的属性方法。
18
19**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
20
21**系统能力:** SystemCapability.ArkUI.ArkUI.Full
22
23**参数:**
24
25| 参数名   | 类型                  | 必填 | 说明                                                         |
26| -------- | --------------------- | ---- | ------------------------------------------------------------ |
27| modifier | [AttributeModifier\<T>](#attributemodifiert) | 是   | 在当前组件上,动态设置属性方法,支持使用if/else语法。<br/>modifier: 属性修改器,开发者需要自定义class实现AttributeModifier接口。 |
28
29## AttributeModifier\<T>
30
31开发者需要自定义class实现AttributeModifier接口。
32
33**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
34
35### applyNormalAttribute
36applyNormalAttribute(instance: T) : void
37
38组件普通状态时的样式。
39
40**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
41
42### applyPressedAttribute
43applyPressedAttribute(instance: T) : void
44
45组件按压状态的样式。
46
47**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
48
49### applyFocusedAttribute
50applyFocusedAttribute(instance: T) : void
51
52组件获焦状态的样式。
53
54**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
55
56### applyDisabledAttribute
57applyDisabledAttribute(instance: T) : void
58
59组件禁用状态的样式。
60
61**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
62
63### applySelectedAttribute
64applySelectedAttribute(instance: T) : void
65
66组件选中状态的样式。
67
68开发者可根据需要自定义实现这些方法,通过传入的参数识别组件类型,对instance设置属性,支持使用if/else语法进行动态设置。
69
70**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
71
72**参数**:
73
74| 参数             | 描述                                                         |
75| -------------------- | ------------------------------------------------------------ |
76| instance |组件的属性类,用来标识进行属性设置的组件的类型,比如Button组件的ButtonAttribute,Text组件的TextAttribute等。|
77
78**instance参数支持范围:**
79
80AlphabetIndexerAttribute、BadgeAttribute、BlankAttribute、ButtonAttribute、CalendarPickerAttribute、CanvasAttribute、CheckboxAttribute、CheckboxGroupAttribute、CircleAttribute、ColumnAttribute、ColumnSplitAttribute、ShapeAttribute、CommonAttribute、CounterAttribute、DataPanelAttribute、DatePickerAttribute、DividerAttribute、EllipseAttribute、FlexAttribute、FlowItemAttribute、FormLinkAttribute、GaugeAttribute、GridAttribute、GridColAttribute、ColumnAttribute、GridItemAttribute、GridRowAttribute、HyperlinkAttribute、ImageAttribute、ImageAnimatorAttribute、ImageSpanAttribute、LineAttribute、ListAttribute、ListItemAttribute、ListItemGroupAttribute、LoadingProgressAttribute、MarqueeAttribute、MenuAttribute、MenuItemAttribute、MenuItemGroupAttribute、NavDestinationAttribute、NavigationAttribute、NavigatorAttribute、NavRouterAttribute、PanelAttribute、PathAttribute、PatternLockAttribute、PolygonAttribute、PolylineAttribute、ProgressAttribute、QRCodeAttribute、RadioAttribute、RatingAttribute、RectAttribute、RefreshAttribute、RelativeContainerAttribute、RichEditorAttribute、RichTextAttribute、RowAttribute、RowSplitAttribute、ScrollAttribute、ScrollBarAttribute、SearchAttribute、SelectAttribute、ShapeAttribute、SideBarContainerAttribute、SliderAttribute、SpanAttribute、StackAttribute、StepperAttribute、StepperItemAttribute、SwiperAttribute、SymbolGlyphAttribute、TabContentAttribute、TabsAttribute、TextAttribute、TextAreaAttribute、TextClockAttribute、TextInputAttribute、TextPickerAttribute、TextTimerAttribute、TimePickerAttribute、ToggleAttribute、VideoAttribute、WaterFlowAttribute、XComponentAttribute、ParticleAttribute<!--Del-->、EffectComponentAttribute、FormComponentAttribute、PluginComponentAttribute、RemoteWindowAttribute、UIExtensionComponentAttribute<!--DelEnd-->。
81
82**属性支持范围:**
83
84不支持入参为[CustomBuilder](ts-types.md#custombuilder8)或Lamda表达式的属性,且不支持手势,事件仅支持onClick、onTouch、onAppear、onDisAppear、onMouse、onHover、onKeyEvent、onBlur、onFocus、onAreaChange、onSizeChange、onGestureJudgeBegin、onGestureRecognizerJudgeBegin、shouldBuiltInRecognizerParallelWith。不支持已废弃属性,未支持的属性在使用时会抛异常"Method not implemented"。
85## 自定义Modifier
86从API version 12开始,开发者可使用自定义Modifier构建组件并配置属性,通过此自定义的Modifier可调用所封装组件的属性和样式接口。
87
88**自定义Modifier支持范围:**
89
90CommonModifier、ColumnModifier、ColumnSplitModifier、RowModifier、RowSplitModifier、SideBarContainerModifier、BlankModifier、DividerModifier、GridColModifier、GridRowModifier、NavDestinationModifier、NavigatorModifier、StackModifier、NavigationModifier、NavRouterModifier、StepperItemModifier、TabsModifier、GridModifier、GridItemModifier、ListModifier、ListItemModifier、ListItemGroupModifier、ScrollModifier、SwiperModifier、WaterFlowModifier、ButtonModifier、CounterModifier、TextPickerModifier、TimePickerModifier、ToggleModifier、CalendarPickerModifier、CheckboxModifier、CheckboxGroupModifier、DatePickerModifier、RadioModifier、RatingModifier、SelectModifier、SliderModifier、PatternLockModifier、SpanModifier、RichEditorModifier、RefreshModifier、SearchModifier、TextAreaModifier、TextModifier、TextInputModifier、ImageSpanModifier、ImageAnimatorModifier、ImageModifier、VideoModifier、DataPanelModifier、GaugeModifier、LoadingProgressModifier、MarqueeModifier、ProgressModifier、QRCodeModifier、TextClockModifier、TextTimerModifier、LineModifier、PathModifier、PolygonModifier、PolylineModifier、RectModifier、ShapeModifier、AlphabetIndexerModifier、FormComponentModifier、HyperlinkModifier、MenuModifier、MenuItemModifier、PanelModifier、SymbolGlyphModifier、ParticleModifier。
91未暴露的组件Modifier可以使用CommonModifier。
92
93**注意事项**
941. 设置自定义Modifier给一个组件,该组件对应属性生效。
952. 自定义Modifier属性值变化,组件对应属性也会变化。自定义Modifier类型为基类,构造的对象为子类对象,使用时要通过as进行类型断言为子类。
963. 一个自定义Modifier设置给两个组件,Modifier属性变化的时候对两个组件同时生效。
974. 一个Modifier设置了属性A和属性B,再设置属性C和属性D,4个属性同时在组件上生效。
985. 自定义Modifier不支持@State标注的状态数据的变化感知,见示例2。
996. 多次通过attributeModifier设置属性时,生效的属性为所有属性的并集,相同属性按照设置顺序生效。
100
101## 示例
102### 示例1(组件绑定Modifier)
103
104该示例通过Button绑定Modifier实现了按压态的效果。如果配合状态管理V2使用,详情见:[Modifier与makeObserved](../../../quick-start/arkts-v1-v2-migration.md#modifier)。
105
106```ts
107// xxx.ets
108class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
109  isDark: boolean = false
110  applyNormalAttribute(instance: ButtonAttribute): void {
111    if (this.isDark) {
112      instance.backgroundColor(Color.Black)
113    } else {
114      instance.backgroundColor(Color.Red)
115    }
116  }
117}
118
119@Entry
120@Component
121struct attributeDemo {
122  @State modifier: MyButtonModifier = new MyButtonModifier()
123
124  build() {
125    Row() {
126      Column() {
127        Button("Button")
128          .attributeModifier(this.modifier)
129          .onClick(() => {
130            this.modifier.isDark = !this.modifier.isDark
131          })
132      }
133      .width('100%')
134    }
135    .height('100%')
136  }
137}
138```
139![attributeModifier_ifelse](figures/attributeModifier_ifelse.gif)
140
141
142
143```ts
144// xxx.ets
145class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
146  applyNormalAttribute(instance: ButtonAttribute): void {
147    instance.backgroundColor(Color.Black)
148  }
149
150  applyPressedAttribute(instance: ButtonAttribute): void {
151    instance.backgroundColor(Color.Red)
152  }
153}
154
155@Entry
156@Component
157struct attributePressedDemo {
158  @State modifier: MyButtonModifier = new MyButtonModifier()
159
160  build() {
161    Row() {
162      Column() {
163        Button("Button")
164          .attributeModifier(this.modifier)
165      }
166      .width('100%')
167    }
168    .height('100%')
169  }
170}
171```
172![attributeModifier_ifelse](figures/attributeModifier_ifelse.gif)
173
174### 示例2(自定义Modifier不支持感知@State装饰的状态数据变化)
175
176该示例通过状态数据设置自定义Modifier的宽度,自定义Modifier不支持感知@State装饰的状态数据变化,点击按钮后宽度不发生改变。
177
178```ts
179import { CommonModifier } from "@kit.ArkUI"
180
181class MyModifier extends CommonModifier {
182  applyNormalAttribute(instance: CommonAttribute) : void{
183    super.applyNormalAttribute?.(instance);
184  }
185}
186
187@Component
188struct MyImage1 {
189  @Link modifier : CommonModifier
190
191  build(){
192    Image($r("app.media.testImage")).attributeModifier(this.modifier as MyModifier)
193  }
194}
195@Entry
196@Component
197struct Index {
198  index : number = 0;
199  @State width1 : number = 100;
200  @State height1 : number = 100;
201  @State myModifier: CommonModifier = new MyModifier().width(this.width1).height(this.height1).margin(10)
202
203  build() {
204    Column() {
205      Button($r("app.string.EntryAbility_label"))
206        .margin(10)
207        .onClick(() => {
208          console.log("Modifier","onClick")
209          this.index ++;
210          if(this.index %2 === 1){
211            this.width1 = 10;
212            console.log("Modifier","setGroup1")
213          }else{
214            this.width1 = 10;
215            console.log("Modifier","setGroup2")
216          }
217        })
218      MyImage1({modifier:this.myModifier})
219    }
220    .width('100%')
221  }
222}
223```
224![attributeModifier2](figures/attributeModifier2.gif)
225
226### 示例3(Modifier和自定义Modifier的属性同时生效)
227
228该示例通过自定义Modifier设置了width和height,点击按钮时设置borderStyle和borderWidth,点击后4个属性同时生效。
229
230```ts
231import { CommonModifier } from "@kit.ArkUI"
232
233class MyModifier extends CommonModifier {
234  applyNormalAttribute(instance: CommonAttribute) : void{
235    super.applyNormalAttribute?.(instance);
236  }
237
238  public setGroup1() : void {
239    this.borderStyle(BorderStyle.Dotted)
240    this.borderWidth(8)
241  }
242
243  public setGroup2() : void {
244    this.borderStyle(BorderStyle.Dashed)
245    this.borderWidth(8)
246  }
247}
248
249@Component
250struct MyImage1 {
251  @Link modifier : CommonModifier
252
253  build(){
254    Image($r("app.media.testImage")).attributeModifier(this.modifier as MyModifier)
255  }
256}
257
258@Entry
259@Component
260struct Index {
261  @State myModifier: CommonModifier = new MyModifier().width(100).height(100).margin(10)
262  index : number = 0;
263
264  build() {
265    Column() {
266      Button($r("app.string.EntryAbility_label"))
267        .margin(10)
268        .onClick(() => {
269          console.log("Modifier","onClick")
270          this.index ++;
271          if(this.index %2 === 1){
272            (this.myModifier as MyModifier).setGroup1()
273            console.log("Modifier","setGroup1")
274          }else{
275            (this.myModifier as MyModifier).setGroup2()
276            console.log("Modifier","setGroup2")
277          }
278        })
279      MyImage1({modifier:this.myModifier})
280    }
281    .width('100%')
282  }
283}
284```
285![attributeModifier](figures/attributeModifier.gif)
286