鸿蒙开发 一 (八)、自定义绘制
做过Android开发的同学对View的自定义绘制应该多少都有点了解,那么再接触鸿蒙的自定义绘制就好上手了。
工具介绍
在Android中常用的工具,和画笔
画布:Canvas
画笔:Paint
在鸿蒙中其实也是这样:
画布:Canvas
画笔:CanvasRenderingContext2D 和 OffscreenCanvasRenderingContext2D
那么这两个画笔有什么区别呢?
- CanvasRenderingContext2D 使用CanvasRenderingContext2D对象在Canvas画布上绘制。
-
OffscreenCanvasRenderingContext2D :离屏绘制,是指将需要绘制的内容先绘制在缓存区,再将其转换成图片,一次性绘制到Canvas上,加快了绘制速度。过程为:
- 通过transferToImageBitmap方法将离屏画布最近渲染的图像创建为一个ImageBitmap对象。
- 通过CanvasRenderingContext2D对象的transferFromImageBitmap方法显示给定的ImageBitmap对象。
常用的方法
//常用方法:
fill() //(对封闭路径进行填充)
stroke() //(进行边框绘制操作)
clip() //(设置当前路径为剪切路径)
fillStyle() //(指定绘制的填充色)
globalAlpha() //(设置透明度)
strokeStyle() //(设置描边的颜色)等属性修改绘制内容的样式
fillText() //(文本填充
strokeText() //(文本描边)
arc() //(绘制弧线路径
ellipse() //(绘制一个椭圆)
rect() //(创建矩形路径)
drawImage() //(图像绘制)
putImageData() //(使用ImageData数据填充新的矩形区域)
createImageData() //(创建新的ImageData 对象
getPixelMap() //(以当前canvas指定区域内的像素创建PixelMap对象
getImageData() //(以当前canvas指定区域内的像素创建ImageData对象
createLinearGradient() //(创建一个线性渐变色)
createRadialGradient() //(创建一个径向渐变色)
代码示例
接下来用一个小例子帮大家熟悉一下鸿蒙的自定义绘制
@ComponentV2
export struct DemoPage {// 配置渲染上下文设置,开启抗锯齿private settings: RenderingContextSettings = new RenderingContextSettings(true);// 创建 2D 渲染上下文private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);// 创建路径对象,用于复杂图形绘制private path: Path2D = new Path2D();// 动态文本内容@Local text: string = 'ArkTS Canvas';aboutToAppear(): void {// 预先定义一个路径,将在 onReady 中使用this.path.arc(150, 500, 50, 0, Math.PI * 2);}build() {Column() {// 标题Text("Canvas API 演示").fontSize(24).fontWeight(FontWeight.Bold).margin({ bottom: 20 })// Canvas 绘制区域Canvas(this.context).width('100%').height('80%').backgroundColor('#f5f5f5').onReady(() => {this.drawScene();})}.width('100%').height('100%').padding(20)}// 绘制整个场景private drawScene(): void {// 清空画布this.context.clearRect(0, 0, 1000, 1000);// 1. 绘制背景 - 使用径向渐变this.drawBackground();// 2. 绘制太阳 - 使用圆形和径向渐变this.drawSun();// 3. 绘制房子 - 使用矩形和路径this.drawHouse();// 4. 绘制树 - 使用路径和填充this.drawTree();// 5. 绘制文本 - 使用填充文本和描边文本this.drawTexts();// 6. 使用预定义路径绘制一个圆this.context.fillStyle = '#3366CC';this.context.fill(this.path);this.context.strokeStyle = '#000000';this.context.lineWidth = 2;this.context.stroke(this.path);}// 绘制渐变背景private drawBackground(): void {// 创建线性渐变 - 从顶部到底部let skyGradient = this.context.createLinearGradient(0, 0, 0, 600);skyGradient.addColorStop(0.0, '#87CEEB'); // 天空蓝skyGradient.addColorStop(0.7, '#E0F7FA'); // 浅蓝skyGradient.addColorStop(1.0, '#81C784'); // 草地绿// 填充背景this.context.fillStyle = skyGradient;this.context.fillRect(0, 0, 1000, 600);}// 绘制太阳private drawSun(): void {// 创建径向渐变let sunGradient = this.context.createRadialGradient(100, 100, 10, 100, 100, 50);sunGradient.addColorStop(0.0, '#FFEB3B'); // 亮黄色sunGradient.addColorStop(1.0, '#FF9800'); // 橙色// 绘制太阳圆形this.context.beginPath();this.context.arc(100, 100, 50, 0, Math.PI * 2);this.context.fillStyle = sunGradient;this.context.fill();// 绘制太阳光芒this.context.strokeStyle = '#FFEB3B';this.context.lineWidth = 3;for (let i = 0; i < 12; i++) {const angle = (Math.PI / 6) * i;this.context.beginPath();this.context.moveTo(100 + Math.cos(angle) * 50, 100 + Math.sin(angle) * 50);this.context.lineTo(100 + Math.cos(angle) * 70, 100 + Math.sin(angle) * 70);this.context.stroke();}}// 绘制房子private drawHouse(): void {// 房子主体 - 矩形this.context.fillStyle = '#795548';this.context.fillRect(300, 300, 200, 150);// 房顶 - 路径this.context.beginPath();this.context.moveTo(300, 300);this.context.lineTo(400, 220);this.context.lineTo(500, 300);this.context.closePath();this.context.fillStyle = '#D32F2F';this.context.fill();// 门 - 矩形this.context.fillStyle = '#5D4037';this.context.fillRect(375, 375, 50, 75);// 窗户 - 矩形和清除区域this.context.fillStyle = '#90CAF9';this.context.fillRect(325, 325, 50, 50);this.context.fillRect(425, 325, 50, 50);// 窗户框架this.context.strokeStyle = '#000000';this.context.lineWidth = 2;this.context.strokeRect(325, 325, 50, 50);this.context.strokeRect(425, 325, 50, 50);// 窗户十字架this.context.beginPath();this.context.moveTo(350, 325);this.context.lineTo(350, 375);this.context.moveTo(325, 350);this.context.lineTo(375, 350);this.context.moveTo(450, 325);this.context.lineTo(450, 375);this.context.moveTo(425, 350);this.context.lineTo(475, 350);this.context.stroke();}// 绘制树private drawTree(): void {// 树干this.context.fillStyle = '#8D6E63';this.context.fillRect(600, 350, 20, 100);// 树叶 - 使用椭圆this.context.fillStyle = '#388E3C';// 底部椭圆this.context.beginPath();this.context.ellipse(610, 350, 60, 40, 0, 0, Math.PI * 2);this.context.fill();// 中间椭圆this.context.beginPath();this.context.ellipse(610, 320, 50, 35, 0, 0, Math.PI * 2);this.context.fill();// 顶部椭圆this.context.beginPath();this.context.ellipse(610, 290, 40, 30, 0, 0, Math.PI * 2);this.context.fill();}// 绘制文本private drawTexts(): void {// 标题文本 - 填充this.context.font = '40px bolder sans-serif';this.context.fillStyle = '#000000';this.context.fillText('美丽的风景', 50, 50);// 动态文本 - 描边this.context.font = '30px sans-serif';this.context.strokeStyle = '#FF5722';this.context.lineWidth = 1;this.context.strokeText(this.text, 50, 580);// 组合文本 - 填充和描边this.context.font = '24px sans-serif';this.context.fillStyle = '#FFFFFF';this.context.fillText('Canvas 绘图示例', 300, 450);this.context.strokeStyle = '#000000';this.context.lineWidth = 0.5;this.context.strokeText('Canvas 绘图示例', 300, 450);}
}