• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Attribute Modifier
2
3With the attribute modifier, you can dynamically set component attributes, complete with the **if/else** syntax and polymorphic style.
4
5> **NOTE**
6>
7> This feature is supported since API version 11. Updates will be marked with a superscript to indicate their earliest API version.
8>
9> Ensure that the attributes set in **attributeModifier** are different from those set in other methods. Otherwise, **attributeModifier** does not take effect when the page is refreshed.
10>
11> **attributeModifier** supports custom components since API version 20.
12
13## attributeModifier
14
15attributeModifier(modifier: AttributeModifier\<T>): T
16
17Creates an attribute modifier.
18
19**Atomic service API**: This API can be used in atomic services since API version 12.
20
21**System capability**: SystemCapability.ArkUI.ArkUI.Full
22
23**Parameters**
24
25| Name  | Type                                        | Mandatory| Description                                                                                                                            |
26| -------- | -------------------------------------------- | ---- | -------------------------------------------------------------------------------------------------------------------------------- |
27| modifier | [AttributeModifier\<T>](#attributemodifiert) | Yes  | Modifier for dynamically setting attributes on the current component. The **if/else** syntax is supported.<br>**modifier**: attribute modifier. You need to customize classes to implement the **AttributeModifier** API.|
28
29**Return value**
30
31| Type| Description|
32| --- | --- |
33| T | Current component.|
34
35## AttributeModifier\<T>
36
37You need a custom class to implement the **AttributeModifier** API.
38
39**Atomic service API**: This API can be used in atomic services since API version 12.
40
41**System capability**: SystemCapability.ArkUI.ArkUI.Full
42
43>  **NOTE**
44>
45>  In the following APIs, setting the same value or object for the same attribute of the **instance** object will not trigger an update.
46
47### applyNormalAttribute
48applyNormalAttribute(instance: T) : void
49
50Applies the style of a component in the normal state.
51
52**Atomic service API**: This API can be used in atomic services since API version 12.
53
54**System capability**: SystemCapability.ArkUI.ArkUI.Full
55
56### applyPressedAttribute
57applyPressedAttribute(instance: T) : void
58
59Applies the style of a component in the pressed state.
60
61**Atomic service API**: This API can be used in atomic services since API version 12.
62
63**System capability**: SystemCapability.ArkUI.ArkUI.Full
64
65### applyFocusedAttribute
66applyFocusedAttribute(instance: T) : void
67
68Applies the style of a component in the focused state.
69
70**Atomic service API**: This API can be used in atomic services since API version 12.
71
72**System capability**: SystemCapability.ArkUI.ArkUI.Full
73
74### applyDisabledAttribute
75applyDisabledAttribute(instance: T) : void
76
77Applies the style of a component in the disabled state.
78
79**Atomic service API**: This API can be used in atomic services since API version 12.
80
81**System capability**: SystemCapability.ArkUI.ArkUI.Full
82
83### applySelectedAttribute
84applySelectedAttribute(instance: T) : void
85
86Applies the style of a component in the selected state.
87
88In the preceding APIs, **instance** indicates the component type. You can customize these APIs and use them with the **if/else **syntax.
89
90**Atomic service API**: This API can be used in atomic services since API version 12.
91
92**System capability**: SystemCapability.ArkUI.ArkUI.Full
93
94**Parameters**
95
96| Name    | Description                                                                                                        |
97| -------- | ------------------------------------------------------------------------------------------------------------ |
98| instance | Component attribute class, which identifies the type of component to which attributes will be applied, for example, **ButtonAttribute** for the **Button** component and **TextAttribute** for the **Text** component.|
99
100**Value range of the instance parameter**
101
102AlphabetIndexerAttribute, 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, IndicatorComponentAttribute, ImageAttribute, ImageAnimatorAttribute, ImageSpanAttribute, LineAttribute, LinearIndicatorAttribute, 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-->
103
104**Supported attributes**
105
1061. Attributes that accept or return a [CustomBuilder](ts-types.md#custombuilder8) are not supported.
1072. Attributes that accept a [modifier](../../../ui/arkts-user-defined-modifier.md) type, such as [attributeModifier](#attributemodifier), [drawModifier](./ts-universal-attributes-draw-modifier.md), and [gestureModifier](./ts-universal-attributes-gesture-modifier.md), are not supported.
1083. Attribute related to [animation](./ts-animatorproperty.md) are not supported.
1094. Attributes of the [gesture](../../../ui/arkts-gesture-events-binding.md) type are not supported.
1105. Attribute related to [stateStyles](./ts-universal-attributes-polymorphic-style.md) are not supported.
1116. Deprecated attributes are not supported.
112<!--Del-->
1137. Built-in component attributes are not supported.<!--DelEnd-->
114
115When unsupported or unimplemented attributes are used, exceptions such as "Method not implemented.", "is not callable", or "Builder is not supported." are thrown. The specific scope of supported attributes is the same as the base class attribute API. For details, see [Supported Scope of Attributes](#supported-scope-of-attributes).
116
117## Custom Modifier
118Custom modifiers can be used in building components and configuring attributes since API version 12. Through the custom modifiers, you can call the attribute and style APIs of encapsulated components.
119
120**Supported custom modifiers**
121
122CommonModifier, 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
123**CommonModifier** can be used for unexposed components.
124
125**Precautions**
1261. When a custom modifier is applied to a component, the corresponding attribute of the component takes effect.
1272. Updating the attribute value of a custom modifier changes the corresponding attribute of the component to which the modifier is applied. The custom modifier is a base class, and the constructed object is a child class object. When using the object, use **as** to assert the type as a child class.
1283. With a custom modifier applied to two components, updating the attribute value of the custom modifier changes the corresponding attributes of both components.
1294. If attributes A and B are set through a custom modifier, and then attributes C and D are set through other means, all the four attributes take effect on the component.
1305. Custom modifiers do not support change detection of state data decorated with @State. For details, see [Example 3: Understanding Custom Modifiers Do Not Support State Data Changes)](#example-3-understanding-custom-modifiers-do-not-support-state-data-changes).
1316. If you use **attributeModifier** to set attributes multiple times, all the set attributes take effect, and those attributes that are set multiple times take effect based on the configuration sequence.
132
133## Example
134### Example 1: Switching the Background Color with a Modifier
135
136This example demonstrates how to switch the background color of a **Button** component by binding it to a modifier.
137
138```ts
139// xxx.ets
140class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
141  public isDark: boolean = false;
142
143  applyNormalAttribute(instance: ButtonAttribute): void {
144    if (this.isDark) {
145      instance.backgroundColor(Color.Black);
146    } else {
147      instance.backgroundColor(Color.Red);
148    }
149  }
150}
151
152@Entry
153@Component
154struct attributeDemo {
155  @State modifier: MyButtonModifier = new MyButtonModifier();
156
157  build() {
158    Row() {
159      Column() {
160        Button("Button")
161          .attributeModifier(this.modifier)
162          .onClick(() => {
163            this.modifier.isDark = !this.modifier.isDark;
164          })
165      }
166      .width('100%')
167    }
168    .height('100%')
169  }
170}
171```
172![attributeModifier_ifelse](figures/attributeModifier_ifelse.gif)
173
174### Example 2: Implementing the Pressed State Effect with a Modifier
175
176This example demonstrates how to implement a pressed state effect for a **Button** component by binding it to a modifier. For details about how to use the attribute modifier with state management V2, see [Modifier and makeObserved](../../../ui/state-management/arkts-v1-v2-migration.md#modifier).
177
178```ts
179// xxx.ets
180class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
181  applyNormalAttribute(instance: ButtonAttribute): void {
182    instance.backgroundColor(Color.Black);
183  }
184
185  applyPressedAttribute(instance: ButtonAttribute): void {
186    instance.backgroundColor(Color.Red);
187  }
188}
189
190@Entry
191@Component
192struct attributePressedDemo {
193  @State modifier: MyButtonModifier = new MyButtonModifier();
194
195  build() {
196    Row() {
197      Column() {
198        Button("Button")
199          .attributeModifier(this.modifier)
200      }
201      .width('100%')
202    }
203    .height('100%')
204  }
205}
206```
207![attributeModifier_ifelse](figures/attributeModifier_ifelse.gif)
208
209### Example 3: Understanding Custom Modifiers Do Not Support State Data Changes
210
211This example shows how to set the width of a custom modifier using state data. Custom modifiers do not support observing changes in data decorated with the @State decorator. Therefore, the width does not change when the button is clicked.
212
213```ts
214import { CommonModifier } from "@kit.ArkUI";
215
216const TEST_TAG : string = "AttributeModifier";
217class MyModifier extends CommonModifier {
218  applyNormalAttribute(instance: CommonAttribute): void {
219    super.applyNormalAttribute?.(instance);
220  }
221}
222
223@Component
224struct MyImage1 {
225  @Link modifier: CommonModifier;
226
227  build() {
228    Image($r("app.media.startIcon")).attributeModifier(this.modifier as MyModifier)
229  }
230}
231
232@Entry
233@Component
234struct Index {
235  index: number = 0;
236  @State width1: number = 100;
237  @State height1: number = 100;
238  @State myModifier: CommonModifier = new MyModifier().width(this.width1).height(this.height1).margin(10);
239
240  build() {
241    Column() {
242      Button($r("app.string.EntryAbility_label"))
243        .margin(10)
244        .onClick(() => {
245          console.log(TEST_TAG, "onClick");
246          this.index++;
247          if (this.index % 2 === 1) {
248            this.width1 = 10;
249            console.log(TEST_TAG, "setGroup1");
250          } else {
251            this.width1 = 10;
252            console.log(TEST_TAG, "setGroup2");
253          }
254        })
255      MyImage1({ modifier: this.myModifier })
256    }
257    .width('100%')
258  }
259}
260```
261![attributeModifier2](figures/attributeModifier2.gif)
262
263### Example 4: Combining Modifier and Custom Modifier Attributes
264
265In this example, the custom modifier sets the **width** and **height** attributes, and the **borderStyle** and **borderWidth** attributes are set through a button click. In this case, all the four attributes take effect when the button is clicked.
266
267```ts
268import { CommonModifier } from "@kit.ArkUI";
269
270const TEST_TAG: string = "AttributeModifier";
271
272class MyModifier extends CommonModifier {
273  applyNormalAttribute(instance: CommonAttribute): void {
274    super.applyNormalAttribute?.(instance);
275  }
276
277  public setGroup1(): void {
278    this.borderStyle(BorderStyle.Dotted);
279    this.borderWidth(8);
280  }
281
282  public setGroup2(): void {
283    this.borderStyle(BorderStyle.Dashed);
284    this.borderWidth(8);
285  }
286}
287
288@Component
289struct MyImage1 {
290  @Link modifier: CommonModifier;
291
292  build() {
293    Image($r("app.media.startIcon")).attributeModifier(this.modifier as MyModifier)
294  }
295}
296
297@Entry
298@Component
299struct Index {
300  @State myModifier: CommonModifier = new MyModifier().width(100).height(100).margin(10);
301  index: number = 0;
302
303  build() {
304    Column() {
305      Button($r("app.string.EntryAbility_label"))
306        .margin(10)
307        .onClick(() => {
308          console.log(TEST_TAG, "onClick");
309          this.index++;
310          if (this.index % 2 === 1) {
311            (this.myModifier as MyModifier).setGroup1();
312            console.log(TEST_TAG, "setGroup1");
313          } else {
314            (this.myModifier as MyModifier).setGroup2();
315            console.log(TEST_TAG, "setGroup2");
316          }
317        })
318      MyImage1({ modifier: this.myModifier })
319    }
320    .width('100%')
321  }
322}
323```
324![attributeModifier](figures/attributeModifier.gif)
325
326### Example 5: Setting the Focused State Style with a Modifier
327
328This example demonstrates how to implement a focused state style for a **Button** component by binding it to a modifier. After **Button2** is clicked, the **Button** component displays the focused style when it has focus.
329
330```ts
331class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
332
333  applyNormalAttribute(instance: ButtonAttribute): void {
334    instance.backgroundColor(Color.Blue);
335  }
336  applyFocusedAttribute(instance: ButtonAttribute): void {
337    instance.backgroundColor(Color.Green);
338  }
339}
340
341@Entry
342@Component
343struct attributeDemo {
344  @State modifier: MyButtonModifier = new MyButtonModifier();
345  @State isDisable: boolean = true;
346
347  build() {
348    Row() {
349      Column() {
350        Button("Button")
351          .attributeModifier(this.modifier)
352          .enabled(this.isDisable)
353          .id("app")
354        Divider().vertical(false).strokeWidth(15).color(Color.Transparent)
355        Button("Button2")
356          .onClick(() => {
357            this.getUIContext().getFocusController().activate(true);
358            this.getUIContext().getFocusController().requestFocus("app");
359          })
360      }
361      .width('100%')
362    }
363    .height('100%')
364  }
365}
366```
367![applyFocusedAttribute](figures/applyFocusedAttribute.gif)
368
369### Example 6: Setting the Disabled State Style with a Modifier
370
371This example demonstrates how to implement a disabled state style for a **Button** component by binding it to a modifier. After **Button2** is clicked, the **Button** component displays the disabled style when it is disabled.
372
373```ts
374class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
375  applyDisabledAttribute(instance: ButtonAttribute): void {
376    instance.width(200);
377  }
378}
379
380@Entry
381@Component
382struct attributeDemo {
383  @State modifier: MyButtonModifier = new MyButtonModifier();
384  @State isDisable: boolean = true;
385
386  build() {
387    Row() {
388      Column() {
389        Button("Button")
390          .attributeModifier(this.modifier)
391          .enabled(this.isDisable)
392        Divider().vertical(false).strokeWidth(15).color(Color.Transparent)
393        Button("Button2")
394          .onClick(() => {
395            this.isDisable = !this.isDisable;
396          })
397      }
398      .width('100%')
399    }
400    .height('100%')
401  }
402}
403```
404![applyDisabledAttribute](figures/applyDisabledAttribute.gif)
405
406### Example 7: Setting the Selected State Style with a Modifier
407
408This example demonstrates how to implement a selected state style for a **Radio** component by binding it to a modifier.
409
410```ts
411class MyRadioModifier implements AttributeModifier<RadioAttribute> {
412  applyNormalAttribute(instance: RadioAttribute): void {
413    instance.backgroundColor(Color.Blue);
414  }
415  applySelectedAttribute(instance: RadioAttribute): void {
416    instance.backgroundColor(Color.Red);
417    instance.borderWidth(2);
418  }
419}
420
421@Entry
422@Component
423struct attributeDemo {
424  @State modifier: MyRadioModifier = new MyRadioModifier();
425  @State value: boolean = false;
426  @State value2: boolean = false;
427
428  build() {
429    Row() {
430      Column() {
431        Radio({ value: 'Radio1', group: 'radioGroup1' })
432          .checked(this.value)
433          .height(50)
434          .width(50)
435          .borderWidth(0)
436          .borderRadius(30)
437          .onClick(() => {
438            this.value = !this.value;
439          })
440          .attributeModifier(this.modifier)
441      }
442      .width('100%')
443    }
444    .height('100%')
445  }
446}
447```
448![applySelectedAttribute](figures/applySelectedAttribute.gif)
449
450### Example 8: Implementing the Pressed State Effect for a Custom Component with a Modifier
451
452This example demonstrates how to implement a pressed state effect for a custom component (**Common**) by binding it to a modifier.
453
454```ts
455// xxx.ets
456class CustomModifier implements AttributeModifier<CommonAttribute> {
457  applyNormalAttribute(instance: CommonAttribute): void {
458    instance.backgroundColor(Color.Blue)
459  }
460
461  applyPressedAttribute(instance: CommonAttribute): void {
462    instance.backgroundColor(Color.Red)
463  }
464}
465
466@Entry
467@Component
468struct attributePressedDemo {
469  @State  modifier: CustomModifier = new CustomModifier()
470
471  build() {
472    Row() {
473      Column() {
474        ChildCompoent()
475          .attributeModifier(this.modifier)
476      }
477      .width('100%')
478    }
479    .height('100%')
480  }
481}
482
483@Component
484struct ChildCompoent {
485  build() {
486    Text("common").fontColor(Color.Green).fontSize(28).textAlign(TextAlign.Center)
487      .width('35%')
488      .height('10%')
489  }
490}
491```
492![attributeModifier_common](figures/attributeModifier_common.gif)
493
494## Supported Scope of Attributes
495
496Attributes not listed in the table below are supported by default.
497
498**Table 1** Unsupported attributes in the CommonAttribute API
499
500| Attribute                    | Supported/Unsupported| Error Message                 | Remarks                                     |
501| ------------------------ | -------- | ------------------------- | ----------------------------------------- |
502| accessibilityChecked     | Not supported  | is not callable           | -                                         |
503| accessibilitySelected    | Not supported  | is not callable           | -                                         |
504| accessibilityTextHint    | Not supported  | is not callable           | -                                         |
505| accessibilityVirtualNode | Not supported  | is not callable           | Attributes that accept a CustomBuilder are not supported.              |
506| animation                | Not supported  | Method not implemented.   | Animation-related attributes are not supported.                |
507| attributeModifier        | Not supported  | -                         | **attributeModifier** does not take effect when nested.|
508| background               | Not supported  | Method not implemented.   | Attributes that accept a CustomBuilder are not supported.              |
509| backgroundFilter         | Not supported  | is not callable           | -                                         |
510| bindContentCover         | Not supported  | Method not implemented.   | Attributes that accept a CustomBuilder are not supported.              |
511| bindContextMenu          | Not supported  | Method not implemented.   | Attributes that accept a CustomBuilder are not supported.              |
512| bindPopup                | Not supported  | Method not implemented.   | Attributes that accept a CustomBuilder are not supported.              |
513| bindSheet                | Not supported  | Method not implemented.   | Attributes that accept a CustomBuilder are not supported.              |
514| chainWeight              | Not supported  | is not callable           | -                                         |
515| compositingFilter        | Not supported  | is not callable           | -                                         |
516| drawModifier             | Not supported  | is not callable           | Modifier-related attributes are not supported.               |
517| foregroundFilter         | Not supported  | is not callable           | -                                         |
518| freeze                   | Not supported  | is not callable           | -                                         |
519| gesture                  | Not supported  | Method not implemented.   | Gesture-related attributes are not supported.                |
520| gestureModifier          | Not supported  | is not callable           | Modifier-related attributes are not supported.               |
521| onAccessibilityHover     | Not supported  | is not callable           | -                                         |
522| onDragStart              | Not supported  | Method not implemented.   | Attributes that return a CustomBuilder are not supported.            |
523| parallelGesture          | Not supported  | Method not implemented.   | Gesture-related attributes are not supported.                |
524| priorityGesture          | Not supported  | Method not implemented.   | Gesture-related attributes are not supported.                |
525| reuseId                  | Not supported  | Method not implemented.   | -                                         |
526| stateStyles              | Not supported  | Method not implemented.   | **stateStyles**-related attributes are not supported.            |
527| useSizeType              | Not supported  | Method not implemented.   | Deprecated attributes are not supported.                       |
528| visualEffect             | Not supported  | is not callable           | -                                         |
529| bindMenu                 | Partially supported| -                         | Attributes that accept a CustomBuilder are not supported.              |
530| dragPreview              | Partially supported| Builder is not supported. | Attributes that accept a CustomBuilder are not supported.              |
531