1# Drawing Modifier
2
3If the drawn content of some components does not meet the requirements, you can use the custom drawing features to draw part or all of the components to achieve the expected effect. For example, you can create buttons in special shapes or icons that mix text and imagery. The drawing modifier offers higher flexibility in your custom drawing.
4
5>  **NOTE**
6>
7>  This feature is supported since API version 12. Updates will be marked with a superscript to indicate their earliest API version.
8
9## drawModifier
10
11drawModifier(modifier: DrawModifier | undefined)
12
13Creates a drawing modifier.
14
15**Atomic service API**: This API can be used in atomic services since API version 12.
16
17**System capability**: SystemCapability.ArkUI.ArkUI.Full
18
19**Supported components:**
20
21AlphabetIndexer, Badge, Blank, Button, CalendarPicker, Checkbox, CheckboxGroup, Circle, Column, ColumnSplit, Counter, DataPanel, DatePicker, Ellipse, Flex, FlowItem, FolderStack, FormLink, Gauge, Grid, GridCol, GridItem, GridRow, Hyperlink, Image, ImageAnimator, ImageSpan, Line, List, ListItem, ListItemGroup, LoadingProgress, Marquee, Menu, MenuItem, MenuItemGroup, NavDestination, Navigation, Navigator, NavRouter, NodeContainer, Path, PatternLock, Polygon, Polyline, Progress, QRCode, Radio, Rating, Rect, Refresh, RelativeContainer, RichEditor, Row, RowSplit, Scroll, ScrollBar, Search, Select, Shape, SideBarContainer, Slider, Stack, Stepper, StepperItem, Swiper, SymbolGlyph, TabContent, Tabs, Text, TextArea, TextClock, TextInput, TextPicker, TextTimer, TimePicker, Toggle, WaterFlow, XComponent
22
23**Parameters**
24
25| Name| Type                                                | Mandatory| Description                                                        |
26| ------ | ---------------------------------------------------- | ---- | ------------------------------------------------------------ |
27| modifier  |  DrawModifier \| undefined | Yes  | Custom drawing modifier, which defines the logic of custom drawing.<br> Default value: **undefined**<br>**NOTE**<br> A custom modifier applies only to the FrameNode of the currently bound component, not to its subnodes.|
28
29## DrawModifier
30
31Implements a **DrawModifier** instance for using the **drawFront**, **drawContent**, and **drawBehind** methods for custom drawing as well as the **invalidate** method for redrawing. Each **DrawModifier** instance can be set for only one component. Repeated setting is not allowed.
32
33**System capability**: SystemCapability.ArkUI.ArkUI.Full
34
35### drawFront
36
37drawFront?(drawContext: DrawContext): void
38
39Draws the foreground. This method can be overloaded for custom foreground drawing.
40
41**Atomic service API**: This API can be used in atomic services since API version 12.
42
43**System capability**: SystemCapability.ArkUI.ArkUI.Full
44
45**Parameters**
46
47| Name | Type                                                  | Mandatory| Description            |
48| ------- | ------------------------------------------------------ | ---- | ---------------- |
49| drawContext | [DrawContext](../js-apis-arkui-graphics.md#drawcontext) | Yes  | Graphics drawing context.|
50
51### drawContent
52
53drawContent?(drawContext: DrawContext): void
54
55Draws the content. This method can be overloaded for custom content drawing. The overloaded method will replace the original content drawing function of the component.
56
57**Atomic service API**: This API can be used in atomic services since API version 12.
58
59**System capability**: SystemCapability.ArkUI.ArkUI.Full
60
61**Parameters**
62
63| Name | Type                                                  | Mandatory| Description            |
64| ------- | ------------------------------------------------------ | ---- | ---------------- |
65| drawContext | [DrawContext](../js-apis-arkui-graphics.md#drawcontext) | Yes  | Graphics drawing context.|
66
67### drawBehind
68
69drawBehind?(drawContext: DrawContext): void
70
71Draws the background. This method can be overloaded for custom background drawing.
72
73**Atomic service API**: This API can be used in atomic services since API version 12.
74
75**System capability**: SystemCapability.ArkUI.ArkUI.Full
76
77**Parameters**
78
79| Name | Type                                                  | Mandatory| Description            |
80| ------- | ------------------------------------------------------ | ---- | ---------------- |
81| drawContext | [DrawContext](../js-apis-arkui-graphics.md#drawcontext) | Yes  | Graphics drawing context.|
82
83
84### invalidate
85
86invalidate(): void
87
88Triggers redrawing of the bound component. No overloading is allowed or needed.
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## Example
95```ts
96// xxx.ets
97import { drawing } from '@kit.ArkGraphics2D';
98import { AnimatorResult } from '@kit.ArkUI';
99
100class MyFullDrawModifier extends DrawModifier {
101  public scaleX: number = 1;
102  public scaleY: number = 1;
103
104  drawBehind(context: DrawContext): void
105  {
106    const brush = new drawing.Brush();
107    brush.setColor({
108      alpha: 255,
109      red: 255,
110      green: 0,
111      blue: 0
112    });
113    context.canvas.attachBrush(brush);
114    const halfWidth = context.size.width / 2;
115    const halfHeight = context.size.width / 2;
116    context.canvas.drawRect({
117      left: vp2px(halfWidth - 50 * this.scaleX),
118      top: vp2px(halfHeight - 50 * this.scaleY),
119      right: vp2px(halfWidth + 50 * this.scaleX),
120      bottom: vp2px(halfHeight + 50 * this.scaleY)
121    });
122  }
123
124  drawContent(context: DrawContext): void
125  {
126    const brush = new drawing.Brush();
127    brush.setColor({
128      alpha: 255,
129      red: 0,
130      green: 255,
131      blue: 0
132    });
133    context.canvas.attachBrush(brush);
134    const halfWidth = context.size.width / 2;
135    const halfHeight = context.size.width / 2;
136    context.canvas.drawRect({
137      left: vp2px(halfWidth - 30 * this.scaleX),
138      top: vp2px(halfHeight - 30 * this.scaleY),
139      right: vp2px(halfWidth + 30 * this.scaleX),
140      bottom: vp2px(halfHeight + 30 * this.scaleY)
141    });
142  }
143
144  drawFront(context: DrawContext): void
145  {
146    const brush = new drawing.Brush();
147    brush.setColor({
148      alpha: 255,
149      red: 0,
150      green: 0,
151      blue: 255
152    });
153    context.canvas.attachBrush(brush);
154    const halfWidth = context.size.width / 2;
155    const halfHeight = context.size.width / 2;
156    const radiusScale = (this.scaleX + this.scaleY) / 2;
157    context.canvas.drawCircle(vp2px(halfWidth), vp2px(halfHeight), vp2px(20 * radiusScale));
158  }
159}
160
161class MyFrontDrawModifier extends DrawModifier {
162  public scaleX: number = 1;
163  public scaleY: number = 1;
164
165  drawFront(context: DrawContext): void
166  {
167    const brush = new drawing.Brush();
168    brush.setColor({
169      alpha: 255,
170      red: 0,
171      green: 0,
172      blue: 255
173    });
174    context.canvas.attachBrush(brush);
175    const halfWidth = context.size.width / 2;
176    const halfHeight = context.size.width / 2;
177    const radiusScale = (this.scaleX + this.scaleY) / 2;
178    context.canvas.drawCircle(vp2px(halfWidth), vp2px(halfHeight), vp2px(20 * radiusScale));
179  }
180}
181
182@Entry
183@Component
184struct DrawModifierExample {
185  private fullModifier: MyFullDrawModifier = new MyFullDrawModifier();
186  private frontModifier: MyFrontDrawModifier = new MyFrontDrawModifier();
187  private drawAnimator: AnimatorResult | undefined = undefined;
188  @State modifier: DrawModifier = new MyFrontDrawModifier();
189  private count = 0;
190
191  create() {
192    let self = this;
193    this.drawAnimator = this.getUIContext().createAnimator({
194      duration: 1000,
195      easing: 'ease',
196      delay: 0,
197      fill: 'forwards',
198      direction: 'normal',
199      iterations: 1,
200      begin: 0,
201      end: 2
202    });
203    this.drawAnimator.onFrame = (value: number) => {
204      console.log('frame value =', value);
205      const tempModifier = self.modifier as MyFullDrawModifier | MyFrontDrawModifier;
206      tempModifier.scaleX = Math.abs(value - 1);
207      tempModifier.scaleY = Math.abs(value - 1);
208      self.modifier.invalidate();
209    };
210  }
211
212  build() {
213    Column() {
214      Row() {
215        Text('test text')
216        .width(100)
217        .height(100)
218        .margin(10)
219        .backgroundColor(Color.Gray)
220        .onClick(() => {
221          const tempModifier = this.modifier as MyFullDrawModifier | MyFrontDrawModifier;
222          tempModifier.scaleX -= 0.1;
223          tempModifier.scaleY -= 0.1;
224        })
225        .drawModifier(this.modifier)
226      }
227      Row() {
228        Button('create')
229        .width(100)
230        .height(100)
231        .margin(10)
232        .onClick(() => {
233          this.create();
234        })
235        Button('play')
236        .width(100)
237        .height(100)
238        .margin(10)
239        .onClick(() => {
240          if (this.drawAnimator) {
241            this.drawAnimator.play();
242          }
243        })
244        Button('changeModifier')
245        .width(100)
246        .height(100)
247        .margin(10)
248        .onClick(() => {
249          this.count += 1;
250          if (this.count % 2 === 1) {
251            console.log('change to full modifier');
252            this.modifier = this.fullModifier;
253          } else {
254            console.log('change to front modifier');
255            this.modifier = this.frontModifier;
256          }
257        })
258      }
259    }
260    .width('100%')
261    .height('100%')
262  }
263}
264```
265
266![drawModifier.gif](figures/drawModifier.gif)
267