鸿蒙开发画布Canvas的核心API使用详解

本文同步发表于我的微信公众号,扫一扫文章底部二维码或微信搜索 程语新视界 即可关注,每个工作日都有文章更新。

一、画布初始化与基础API

1. 画布创建
@Entry
@Component
struct CanvasExample {
  private settings: RenderingContextSettings = new RenderingContextSettings(true) // 开启抗锯齿
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  build() {
    Column() {
      Canvas(this.context)//传入画笔
        .width('100%')
        .height(400)
        .backgroundColor('#F0F4FD')
        .onReady(() => { /* 绘制逻辑 */ })
    }
  }
}

关键点

  • RenderingContextSettings 控制抗锯齿等渲染特性
  • onReady 回调确保画布尺寸就绪 

二、图形绘制API

1. 基础形状
// 矩形(填充+描边)
context.fillStyle = '#4ECDC4' 
context.fillRect(50, 50, 200, 150)
context.strokeStyle = '#556270'
context.strokeRect(45, 45, 210, 160)

// 圆形
context.beginPath()
context.arc(300, 120, 50, 0, 2 * Math.PI)
context.fill()

参数说明

  • arc(x, y, 半径, 起始角, 结束角) 绘制圆弧路径 
2. 路径操作
// 自定义路径
let path = new Path2D()
path.moveTo(100, 100)
path.lineTo(200, 150)
path.quadraticCurveTo(250, 200, 300, 180) // 二次贝塞尔曲线
context.stroke(path)

方法链

  • beginPath() 开始新路径 → moveTo() 移动起点 → 绘制指令 → stroke()/fill() 完成绘制

三、高级渲染技术

1. 离屏渲染(性能优化)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)

// 离屏绘制
const offContext = this.offCanvas.getContext("2d")
offContext.drawImage(imageSource, 0, 0, 600, 600)

// 合并到主画布
const bitmap = offCanvas.transferToImageBitmap()
context.transferFromImageBitmap(bitmap)

优势

  • 减少主线程阻塞,适合复杂动画 
2. 渐变与阴影
// 线性渐变
const grad = context.createLinearGradient(0, 0, 400, 0)
grad.addColorStop(0, '#E87361')
grad.addColorStop(1, '#BDDB69')
context.fillStyle = grad
context.fillRect(0, 0, 400, 400)

// 阴影效果
context.shadowBlur = 15
context.shadowColor = 'rgba(0,0,0,0.5)'
context.shadowOffsetX = 5

特效参数

  • shadowBlur 控制模糊半径,shadowOffset 设置偏移量

四、图像与文本处理

1. 图像绘制
// 加载图片
const img = new Image()
img.src = 'common/images/logo.png'
img.onload = () => {
  context.drawImage(img, 100, 100, 200, 200) // 缩放绘制
}

支持模式

  • drawImage(image, dx, dy) 原始尺寸
  • drawImage(image, dx, dy, dWidth, dHeight) 自定义尺寸
2. 文本渲染
context.font = 'bold 36px sans-serif'
context.textAlign = 'center'
context.fillStyle = '#333'
context.fillText('HarmonyOS', 200, 300)

文本属性

  • textBaseline 控制基线对齐方式
  • strokeText() 实现描边文字 

五、交互与beginPath路径

1. 触摸事件处理
Canvas(this.context)
  .onTouch((event: TouchEvent) => {
    const x = event.touches[0].x
    const y = event.touches[0].y
    drawCircle(x, y) // 实时绘制触点
  })
2. 路径重置与隔离
// 错误示例:未使用beginPath导致样式覆盖
ctx.strokeStyle = "blue";
ctx.moveTo(0, 0);
ctx.lineTo(100, 0);
ctx.stroke();

ctx.strokeStyle = "red"; 
ctx.lineTo(100, 100); // 红色会覆盖蓝色路径
ctx.stroke();
  • 功能beginPath() 用于开始新的绘制路径或清空当前路径列表,确保后续绘制操作不与之前的路径叠加。
  • 必要性:若不调用,所有图形会共享同一路径,导致样式覆盖或重复绘制(如线条颜色混合) 。

3.路径生命周期管理

路径构建流程beginPath() → 路径定义(如moveTo/lineTo) → stroke()fill() → 再次beginPath() 。

使用场景与最佳实践

1. 多图形独立绘制

需为每个图形单独调用 beginPath,避免路径干扰:

// 绘制两条独立线段(蓝色水平线 + 绿色斜线)
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.moveTo(20, 20);
ctx.lineTo(200, 20);
ctx.stroke();

ctx.beginPath(); // 重置路径
ctx.strokeStyle = "green";
ctx.moveTo(20, 20);
ctx.lineTo(120, 120);
ctx.stroke();

效果:两条线段颜色独立,互不影响

2. 复杂图形组合

结合 closePath() 闭合路径,生成完整形状:

ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(150, 50);
ctx.lineTo(150, 150);
ctx.lineTo(50, 150);
ctx.closePath(); // 闭合为矩形
ctx.strokeStyle = "#333";
ctx.stroke();

说明closePath() 自动连接起点与终点,形成闭合路径。

3. 动态交互绘制

在触摸事件中,每次绘制前需重置路径:

Canvas(this.context)
  .onTouch((e: TouchEvent) => {
    ctx.beginPath(); // 每次触摸开始新路径
    ctx.arc(e.touches[0].x, e.touches[0].y, 10, 0, 2*Math.PI);
    ctx.fill();
  })

五、常见错误与调试

1. 路径未闭合导致填充异常
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(150, 50);
ctx.lineTo(150, 150);
ctx.fill(); // 未闭合时填充区域不确定

修复:添加 closePath() 或手动闭合路径。

2. 样式污染问题

若多个图形共享同一路径,最后一次设置的样式会覆盖之前的所有图形。

解决方案:每个图形独立使用 beginPath + 样式设置。

六、核心对象参考

对象 关键方法/属性 说明
CanvasRenderingContext2D fillRect()strokeText()globalAlpha 主绘制上下文 
OffscreenCanvas transferToImageBitmap() 离屏画布对象 
Path2D arc()quadraticCurveTo() 路径定义对象 
Image onloadsrc 图像加载对象 

完整API文档可参考鸿蒙开发者文档中心,实际开发中建议结合离屏渲染与路径复用提升性能。

你可能感兴趣的:(前端,华为,鸿蒙,harmonyos)