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 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 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 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 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 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 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 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 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