1# 自定义绘制设置 2 3当某些组件本身的绘制内容不满足需求时,可使用自定义组件绘制功能,在原有组件基础上部分绘制、或者全部自行绘制,以达到预期效果。例如:独特的按钮形状、文字和图像混合的图标等。自定义组件绘制提供了自定义绘制修改器,来实现更自由地组件绘制。 4 5> **说明:** 6> 7> 从API Version 12开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 8 9## drawModifier 10 11drawModifier(modifier: DrawModifier | undefined) 12 13设置组件的自定义绘制修改器。 14 15**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 16 17**系统能力:** SystemCapability.ArkUI.ArkUI.Full 18 19**组件支持范围:** 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**参数:** 24 25| 参数名 | 类型 | 必填 | 说明 | 26| ------ | ---------------------------------------------------- | ---- | ------------------------------------------------------------ | 27| modifier | [DrawModifier](#drawmodifier-1) \| undefined | 是 | 自定义绘制修改器,其中定义了自定义绘制的逻辑。 <br> 默认值:undefined <br/>**说明:** <br/> 每个自定义修改器只对当前绑定组件的FrameNode生效,对其子节点不生效。 | 28 29## DrawModifier 30 31DrawModifier可设置前景(drawFront)、内容(drawContent)和背景(drawBehind)的绘制方法,还提供主动触发重绘的方法invalidate。每个DrawModifier实例只能设置到一个组件上,禁止进行重复设置。 32 33**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 34 35**系统能力:** SystemCapability.ArkUI.ArkUI.Full 36 37### drawFront 38 39drawFront?(drawContext: DrawContext): void 40 41自定义绘制前景的接口,若重载该方法则可进行前景的自定义绘制。 42 43**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 44 45**系统能力:** SystemCapability.ArkUI.ArkUI.Full 46 47**参数:** 48 49| 参数名 | 类型 | 必填 | 说明 | 50| ------- | ------------------------------------------------------ | ---- | ---------------- | 51| drawContext | [DrawContext](../js-apis-arkui-graphics.md#drawcontext) | 是 | 图形绘制上下文。 | 52 53### drawContent 54 55drawContent?(drawContext: DrawContext): void 56 57自定义绘制内容的接口,若重载该方法可进行内容的自定义绘制,会替换组件原本的内容绘制函数。 58 59**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 60 61**系统能力:** SystemCapability.ArkUI.ArkUI.Full 62 63**参数:** 64 65| 参数名 | 类型 | 必填 | 说明 | 66| ------- | ------------------------------------------------------ | ---- | ---------------- | 67| drawContext | [DrawContext](../js-apis-arkui-graphics.md#drawcontext) | 是 | 图形绘制上下文。 | 68 69### drawBehind 70 71drawBehind?(drawContext: DrawContext): void 72 73自定义绘制背景的接口,若重载该方法则可进行背景的自定义绘制。 74 75**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 76 77**系统能力:** SystemCapability.ArkUI.ArkUI.Full 78 79**参数:** 80 81| 参数名 | 类型 | 必填 | 说明 | 82| ------- | ------------------------------------------------------ | ---- | ---------------- | 83| drawContext | [DrawContext](../js-apis-arkui-graphics.md#drawcontext) | 是 | 图形绘制上下文。 | 84 85 86### invalidate 87 88invalidate(): void 89 90主动触发重绘的接口,开发者无需也无法重载,调用会触发所绑定组件的重绘。 91 92**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 93 94**系统能力:** SystemCapability.ArkUI.ArkUI.Full 95 96## 示例 97 98通过DrawModifier对Text组件进行自定义绘制。 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 uiContext: UIContext; 109 110 constructor(uiContext: UIContext) { 111 super(); 112 this.uiContext = uiContext; 113 } 114 115 drawBehind(context: DrawContext): void { 116 const brush = new drawing.Brush(); 117 brush.setColor({ 118 alpha: 255, 119 red: 255, 120 green: 0, 121 blue: 0 122 }); 123 context.canvas.attachBrush(brush); 124 const halfWidth = context.size.width / 2; 125 const halfHeight = context.size.width / 2; 126 context.canvas.drawRect({ 127 left: this.uiContext.vp2px(halfWidth - 50 * this.scaleX), 128 top: this.uiContext.vp2px(halfHeight - 50 * this.scaleY), 129 right: this.uiContext.vp2px(halfWidth + 50 * this.scaleX), 130 bottom: this.uiContext.vp2px(halfHeight + 50 * this.scaleY) 131 }); 132 } 133 134 drawContent(context: DrawContext): void { 135 const brush = new drawing.Brush(); 136 brush.setColor({ 137 alpha: 255, 138 red: 0, 139 green: 255, 140 blue: 0 141 }); 142 context.canvas.attachBrush(brush); 143 const halfWidth = context.size.width / 2; 144 const halfHeight = context.size.width / 2; 145 context.canvas.drawRect({ 146 left: this.uiContext.vp2px(halfWidth - 30 * this.scaleX), 147 top: this.uiContext.vp2px(halfHeight - 30 * this.scaleY), 148 right: this.uiContext.vp2px(halfWidth + 30 * this.scaleX), 149 bottom: this.uiContext.vp2px(halfHeight + 30 * this.scaleY) 150 }); 151 } 152 153 drawFront(context: DrawContext): void { 154 const brush = new drawing.Brush(); 155 brush.setColor({ 156 alpha: 255, 157 red: 0, 158 green: 0, 159 blue: 255 160 }); 161 context.canvas.attachBrush(brush); 162 const halfWidth = context.size.width / 2; 163 const halfHeight = context.size.width / 2; 164 const radiusScale = (this.scaleX + this.scaleY) / 2; 165 context.canvas.drawCircle(this.uiContext.vp2px(halfWidth), this.uiContext.vp2px(halfHeight), this.uiContext.vp2px(20 * radiusScale)); 166 } 167} 168 169class MyFrontDrawModifier extends DrawModifier { 170 public scaleX: number = 1; 171 public scaleY: number = 1; 172 uiContext: UIContext; 173 174 constructor(uiContext: UIContext) { 175 super(); 176 this.uiContext = uiContext; 177 } 178 179 drawFront(context: DrawContext): void { 180 const brush = new drawing.Brush(); 181 brush.setColor({ 182 alpha: 255, 183 red: 0, 184 green: 0, 185 blue: 255 186 }); 187 context.canvas.attachBrush(brush); 188 const halfWidth = context.size.width / 2; 189 const halfHeight = context.size.width / 2; 190 const radiusScale = (this.scaleX + this.scaleY) / 2; 191 context.canvas.drawCircle(this.uiContext.vp2px(halfWidth), this.uiContext.vp2px(halfHeight), this.uiContext.vp2px(20 * radiusScale)); 192 } 193} 194 195@Entry 196@Component 197struct DrawModifierExample { 198 private fullModifier: MyFullDrawModifier = new MyFullDrawModifier(this.getUIContext()); 199 private frontModifier: MyFrontDrawModifier = new MyFrontDrawModifier(this.getUIContext()); 200 private drawAnimator: AnimatorResult | undefined = undefined; 201 @State modifier: DrawModifier = new MyFrontDrawModifier(this.getUIContext()); 202 private count = 0; 203 204 create() { 205 let self = this; 206 this.drawAnimator = this.getUIContext().createAnimator({ 207 duration: 1000, 208 easing: 'ease', 209 delay: 0, 210 fill: 'forwards', 211 direction: 'normal', 212 iterations: 1, 213 begin: 0, 214 end: 2 215 }); 216 this.drawAnimator.onFrame = (value: number) => { 217 console.log('frame value =', value); 218 const tempModifier = self.modifier as MyFullDrawModifier | MyFrontDrawModifier; 219 tempModifier.scaleX = Math.abs(value - 1); 220 tempModifier.scaleY = Math.abs(value - 1); 221 self.modifier.invalidate(); 222 }; 223 } 224 225 build() { 226 Column() { 227 Row() { 228 Text('test text') 229 .width(100) 230 .height(100) 231 .margin(10) 232 .backgroundColor(Color.Gray) 233 .onClick(() => { 234 const tempModifier = this.modifier as MyFullDrawModifier | MyFrontDrawModifier; 235 tempModifier.scaleX -= 0.1; 236 tempModifier.scaleY -= 0.1; 237 }) 238 .drawModifier(this.modifier) 239 } 240 241 Row() { 242 Button('create') 243 .width(100) 244 .height(100) 245 .margin(10) 246 .onClick(() => { 247 this.create(); 248 }) 249 Button('play') 250 .width(100) 251 .height(100) 252 .margin(10) 253 .onClick(() => { 254 if (this.drawAnimator) { 255 this.drawAnimator.play(); 256 } 257 }) 258 Button('changeModifier') 259 .width(100) 260 .height(100) 261 .margin(10) 262 .onClick(() => { 263 this.count += 1; 264 if (this.count % 2 === 1) { 265 console.log('change to full modifier'); 266 this.modifier = this.fullModifier; 267 } else { 268 console.log('change to front modifier'); 269 this.modifier = this.frontModifier; 270 } 271 }) 272 } 273 } 274 .width('100%') 275 .height('100%') 276 } 277} 278``` 279 280 281