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](#drawmodifier-1) \| 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**Atomic service API**: This API can be used in atomic services since API version 12. 34 35**System capability**: SystemCapability.ArkUI.ArkUI.Full 36 37### drawFront 38 39drawFront?(drawContext: DrawContext): void 40 41Draws the foreground. This method can be overloaded for custom foreground drawing. 42 43**Atomic service API**: This API can be used in atomic services since API version 12. 44 45**System capability**: SystemCapability.ArkUI.ArkUI.Full 46 47**Parameters** 48 49| Name | Type | Mandatory| Description | 50| ------- | ------------------------------------------------------ | ---- | ---------------- | 51| drawContext | [DrawContext](../js-apis-arkui-graphics.md#drawcontext) | Yes | Graphics drawing context.| 52 53### drawContent 54 55drawContent?(drawContext: DrawContext): void 56 57Draws the content. This method can be overloaded for custom content drawing. The overloaded method will replace the original content drawing function of the component. 58 59**Atomic service API**: This API can be used in atomic services since API version 12. 60 61**System capability**: SystemCapability.ArkUI.ArkUI.Full 62 63**Parameters** 64 65| Name | Type | Mandatory| Description | 66| ------- | ------------------------------------------------------ | ---- | ---------------- | 67| drawContext | [DrawContext](../js-apis-arkui-graphics.md#drawcontext) | Yes | Graphics drawing context.| 68 69### drawBehind 70 71drawBehind?(drawContext: DrawContext): void 72 73Draws the background. This method can be overloaded for custom background drawing. 74 75**Atomic service API**: This API can be used in atomic services since API version 12. 76 77**System capability**: SystemCapability.ArkUI.ArkUI.Full 78 79**Parameters** 80 81| Name | Type | Mandatory| Description | 82| ------- | ------------------------------------------------------ | ---- | ---------------- | 83| drawContext | [DrawContext](../js-apis-arkui-graphics.md#drawcontext) | Yes | Graphics drawing context.| 84 85 86### invalidate 87 88invalidate(): void 89 90Triggers redrawing of the bound component. No overloading is allowed or needed. 91 92**Atomic service API**: This API can be used in atomic services since API version 12. 93 94**System capability**: SystemCapability.ArkUI.ArkUI.Full 95 96## Example 97 98This example shows how to customize the drawing of a **Text** component using **DrawModifier**. 99 100```ts 101// xxx.ets 102import { drawing } from '@kit.ArkGraphics2D'; 103import { AnimatorResult } from '@kit.ArkUI'; 104 105class MyFullDrawModifier extends DrawModifier { 106 public scaleX: number = 1; 107 public scaleY: number = 1; 108 109 drawBehind(context: DrawContext): void { 110 const brush = new drawing.Brush(); 111 brush.setColor({ 112 alpha: 255, 113 red: 255, 114 green: 0, 115 blue: 0 116 }); 117 context.canvas.attachBrush(brush); 118 const halfWidth = context.size.width / 2; 119 const halfHeight = context.size.width / 2; 120 context.canvas.drawRect({ 121 left: vp2px(halfWidth - 50 * this.scaleX), 122 top: vp2px(halfHeight - 50 * this.scaleY), 123 right: vp2px(halfWidth + 50 * this.scaleX), 124 bottom: vp2px(halfHeight + 50 * this.scaleY) 125 }); 126 } 127 128 drawContent(context: DrawContext): void { 129 const brush = new drawing.Brush(); 130 brush.setColor({ 131 alpha: 255, 132 red: 0, 133 green: 255, 134 blue: 0 135 }); 136 context.canvas.attachBrush(brush); 137 const halfWidth = context.size.width / 2; 138 const halfHeight = context.size.width / 2; 139 context.canvas.drawRect({ 140 left: vp2px(halfWidth - 30 * this.scaleX), 141 top: vp2px(halfHeight - 30 * this.scaleY), 142 right: vp2px(halfWidth + 30 * this.scaleX), 143 bottom: vp2px(halfHeight + 30 * this.scaleY) 144 }); 145 } 146 147 drawFront(context: DrawContext): void { 148 const brush = new drawing.Brush(); 149 brush.setColor({ 150 alpha: 255, 151 red: 0, 152 green: 0, 153 blue: 255 154 }); 155 context.canvas.attachBrush(brush); 156 const halfWidth = context.size.width / 2; 157 const halfHeight = context.size.width / 2; 158 const radiusScale = (this.scaleX + this.scaleY) / 2; 159 context.canvas.drawCircle(vp2px(halfWidth), vp2px(halfHeight), vp2px(20 * radiusScale)); 160 } 161} 162 163class MyFrontDrawModifier extends DrawModifier { 164 public scaleX: number = 1; 165 public scaleY: number = 1; 166 167 drawFront(context: DrawContext): void { 168 const brush = new drawing.Brush(); 169 brush.setColor({ 170 alpha: 255, 171 red: 0, 172 green: 0, 173 blue: 255 174 }); 175 context.canvas.attachBrush(brush); 176 const halfWidth = context.size.width / 2; 177 const halfHeight = context.size.width / 2; 178 const radiusScale = (this.scaleX + this.scaleY) / 2; 179 context.canvas.drawCircle(vp2px(halfWidth), vp2px(halfHeight), vp2px(20 * radiusScale)); 180 } 181} 182 183@Entry 184@Component 185struct DrawModifierExample { 186 private fullModifier: MyFullDrawModifier = new MyFullDrawModifier(); 187 private frontModifier: MyFrontDrawModifier = new MyFrontDrawModifier(); 188 private drawAnimator: AnimatorResult | undefined = undefined; 189 @State modifier: DrawModifier = new MyFrontDrawModifier(); 190 private count = 0; 191 192 create() { 193 let self = this; 194 this.drawAnimator = this.getUIContext().createAnimator({ 195 duration: 1000, 196 easing: 'ease', 197 delay: 0, 198 fill: 'forwards', 199 direction: 'normal', 200 iterations: 1, 201 begin: 0, 202 end: 2 203 }); 204 this.drawAnimator.onFrame = (value: number) => { 205 console.log('frame value =', value); 206 const tempModifier = self.modifier as MyFullDrawModifier | MyFrontDrawModifier; 207 tempModifier.scaleX = Math.abs(value - 1); 208 tempModifier.scaleY = Math.abs(value - 1); 209 self.modifier.invalidate(); 210 }; 211 } 212 213 build() { 214 Column() { 215 Row() { 216 Text('test text') 217 .width(100) 218 .height(100) 219 .margin(10) 220 .backgroundColor(Color.Gray) 221 .onClick(() => { 222 const tempModifier = this.modifier as MyFullDrawModifier | MyFrontDrawModifier; 223 tempModifier.scaleX -= 0.1; 224 tempModifier.scaleY -= 0.1; 225 }) 226 .drawModifier(this.modifier) 227 } 228 229 Row() { 230 Button('create') 231 .width(100) 232 .height(100) 233 .margin(10) 234 .onClick(() => { 235 this.create(); 236 }) 237 Button('play') 238 .width(100) 239 .height(100) 240 .margin(10) 241 .onClick(() => { 242 if (this.drawAnimator) { 243 this.drawAnimator.play(); 244 } 245 }) 246 Button('changeModifier') 247 .width(100) 248 .height(100) 249 .margin(10) 250 .onClick(() => { 251 this.count += 1; 252 if (this.count % 2 === 1) { 253 console.log('change to full modifier'); 254 this.modifier = this.fullModifier; 255 } else { 256 console.log('change to front modifier'); 257 this.modifier = this.frontModifier; 258 } 259 }) 260 } 261 } 262 .width('100%') 263 .height('100%') 264 } 265} 266``` 267 268 269