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 267