HarmonyOS Canvas开发指南

HarmonyOS Canvas开发指南:从基础绘制到高级应用

在鸿蒙应用开发中,当系统组件无法满足复杂视觉需求时,Canvas画布便成为了实现自定义绘制的核心技术。本文将系统介绍HarmonyOS中Canvas的使用方法,从基础概念到高级应用,帮助你掌握自定义图形的绘制技巧。

一、Canvas基础概念

在HarmonyOS中,Canvas是一个画布组件,作为绘制的容器,提供了两种主要的绘制上下文对象:

  • **DrawingRenderingContext**:基础绘制工具

  • **CanvasRenderingContext2D**:功能更丰富的2D绘制工具(推荐使用)

与Web中的Canvas类似,HarmonyOS的Canvas支持绘制图形、文本、图像等元素,适用于股票行情图、基金折线图等高度定制化的视觉场景。

创建Canvas组件

在ArkUI中创建Canvas组件的基本结构如下:

```typescript

复制代码
@Entry
@Component
struct CanvasDemo {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  
  build() {
    Canvas(this.context)
      .width('100%')
      .height('100%')
      .backgroundColor('#ffff00')
      .onReady(() => {
        // 绘制操作在此进行
      })
  }
}

```

**注意**:绘制操作必须在Canvas的`onReady`回调方法中进行,以确保组件初始化完成。

二、两种绘制上下文对比

1. DrawingRenderingContext

DrawingRenderingContext是基础的绘制工具,包含三个主要成员:

  • **size**:Context大小的宽和高

  • **canvas**:绘制模块的Canvas对象

  • **invalidate()**:使组件无效,触发重新渲染简单使用示例:

```typescript

复制代码
@Entry
@Component
struct DrawingExample {
  private context: DrawingRenderingContext = new DrawingRenderingContext()
  
  build() {
    Canvas(this.context)
      .width("100%")
      .height("100%")
      .onReady(() => {
        this.context.canvas.drawCircle(200, 200, 100)
        this.context.invalidate()
      })
  }
}
```

### 2. CanvasRenderingContext2D

CanvasRenderingContext2D提供了更丰富的属性和方法,使用起来更加方便,特别是在修改画笔粗细、颜色等属性时。

```typescript
@Entry
@Component
struct Canvas2DExample {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  
  build() {
    Canvas(this.context)
      .width('100%')
      .height('100%')
      .onReady(() => {
        this.context.fillRect(0, 0, 100, 100)
      })
  }
}

```

三、基本图形绘制

绘制矩形

```

复制代码
CanvasRenderingContext2D提供了多种绘制矩形的方法:

```typescript
// 填充矩形
ctx.fillStyle = '#0000ff'
ctx.fillRect(20, 20, 150, 100)

// 描边矩形
ctx.lineWidth = 10
ctx.strokeStyle = '#0000ff'
ctx.strokeRect(25, 25, 155, 105)

// 创建矩形路径
ctx.rect(20, 20, 100, 100)
ctx.stroke()
```

### 绘制圆形和弧线

```typescript
// 绘制圆形
ctx.beginPath()
ctx.arc(100, 75, 50, 0, 6.28) // 6.28≈2π,完整圆形
ctx.stroke()

// 使用DrawingRenderingContext绘制圆形
context.canvas.drawCircle(200, 200, 100)
```

### 绘制路径

路径绘制允许创建复杂形状:

```typescript
// 直线路径
ctx.beginPath()
ctx.moveTo(10, 10)
ctx.lineTo(280, 160)
ctx.stroke()

// 封闭路径
ctx.beginPath()
ctx.moveTo(30, 30)
ctx.lineTo(110, 30)
ctx.lineTo(70, 90)
ctx.closePath()
ctx.stroke()
```

### 绘制文本

```typescript
// 填充文本
ctx.font = '35px sans-serif'
ctx.fillText("Hello World!", 20, 60)

// 设置文本对齐方式
ctx.textAlign = 'center'
ctx.fillText('文本居中对齐', 140, 120)

四、高级绘制技巧

1. 使用createPattern创建填充模板

`createPattern`方法允许使用图像创建填充模板,支持多种重复方式:```typescript

复制代码
@Entry
@Component
struct PatternExample {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private img: ImageBitmap = new ImageBitmap("/images/2.png")

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#ffff00')
        .onReady(() => {
          // 创建填充模版
          let pattern = this.context.createPattern(this.img, 'repeat') // 支持 repeat, repeat-x, repeat-y, no-repeat, clamp, mirror
          if (pattern) {
            this.context.fillStyle = pattern
          }
          // 使用模板填充矩形
          this.context.fillRect(0, 0, 400, 400)
        })
    }
    .width('100%')
    .height('100%')
  }
}

```

2. 贝塞尔曲线

```

复制代码
**二次贝塞尔曲线**:
```typescript
ctx.beginPath()
ctx.moveTo(20, 20)
ctx.quadraticCurveTo(100, 100, 200, 20) // (cpx, cpy, x, y)
ctx.stroke()
```

**三次贝塞尔曲线**:
```typescript
ctx.beginPath()
ctx.moveTo(10, 10)
ctx.bezierCurveTo(20, 100, 200, 100, 200, 20) // (cp1x, cp1y, cp2x, cp2y, x, y)
ctx.stroke()
```

### 3. 变换和倾斜效果

使用`setTransform`可以实现图形的倾斜、旋转等变换效果:

```typescript
// 设置变换矩阵,绘制倾斜文字
this.context.setTransform(1, -0.5, 0.5, 1, 10, 10)
this.context.font = '30px sans-serif'
this.context.fillText("倾斜文字", 20, 60)
```

### 4. ImageData像素级操作

ImageData对象可以存储canvas渲染的像素数据,实现对每个像素的操作:

```typescript
// 获取ImageData数据
const imageData = ctx.getImageData(0, 0, 130, 130)

// 处理像素数据
// imageData.data 是包含RGBA顺序数据的Uint8ClampedArray

// 将处理后的数据重新绘制到画布
ctx.putImageData(imageData, 0, 0)

五、性能优化技巧

在鸿蒙应用开发中,图形渲染优化直接影响应用流畅度和用户体验。

1. 减少不必要的重绘

避免频繁触发`invalidate()`,仅在数据变更时更新UI:

```typescript

复制代码
@State text: string = "初始状态"
@Component
struct MyText {
  build() {
    Text(this.text).onClick(() => {
      // 仅在状态实际改变时触发更新
      if (this.text !== "更新") {
        this.text = "更新"
      }
    })
  }
}

```

2. 使用离屏缓存

对于复杂UI绘制,可使用离屏缓存预渲染图形:

```

复制代码
```typescript
@Entry
@Component
struct CachedDrawing {
  private cache = CanvasCache.create(200, 200)
  
  build() {
    if (!this.cache.isValid()) {
      this.cache.drawRect({x: 0, y: 0, width: 200, height: 200, color: Color.Red})
    }
    CanvasContext().drawCache(this.cache)
  }
}
```

### 3. 优化动画性能

- 使用`ImplicitAnimation`代替`setInterval()`
- 合并多个动画帧,减少刷新频率
- 避免在主线程执行过多计算

```typescript
@Entry
@Component
struct SmoothAnimation {
  @State scale: number = 1
  
  build() {
    Image("icon.png")
      .scale(this.scale)
      .animate({ duration: 300, curve: Curve.EaseInOut })
      .onAppear(() => this.scale = 1.2)
  }
}

六、实战案例:简单涂鸦板

以下是一个使用Canvas实现的简单涂鸦板示例:

```

复制代码
```typescript
@Entry
@Component
struct DoodleBoard {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private isDrawing: boolean = false
  private lastX: number = 0
  private lastY: number = 0
  private brushColor: string = 'black'
  private brushSize: number = 5

  build() {
    Column() {
      // 画笔设置区域
      Row() {
        Button('黑色').onClick(() => { this.brushColor = 'black' })
        Button('红色').onClick(() => { this.brushColor = 'red' })
        Button('蓝色').onClick(() => { this.brushColor = 'blue' })
        Button('清除').onClick(() => { this.clearCanvas() })
      }
      .padding(10)

      // 画布区域
      Canvas(this.context)
        .width('100%')
        .height('80%')
        .backgroundColor('#ffffff')
        .onTouch((event) => {
          this.handleTouch(event)
        })
    }
  }

  handleTouch(event: TouchEvent) {
    const x = event.touches[0].x
    const y = event.touches[0].y

    switch (event.type) {
      case TouchType.Down:
        this.isDrawing = true
        this.lastX = x
        this.lastY = y
        break
        
      case TouchType.Move:
        if (this.isDrawing) {
          this.context.beginPath()
          this.context.moveTo(this.lastX, this.lastY)
          this.context.lineTo(x, y)
          this.context.strokeStyle = this.brushColor
          this.context.lineWidth = this.brushSize
          this.context.stroke()
          ;[this.lastX, this.lastY] = [x, y]
        }
        break
        
      case TouchType.Up:
        this.isDrawing = false
        break
    }
  }

  clearCanvas() {
    this.context.clearRect(0, 0, 1000, 1000) // 根据实际Canvas尺寸调整
  }
}

七、AI增强功能

从API 12开始,HarmonyOS的Canvas增加了AI分析选项参数`ImageAIOptions`,可配置分析类型或绑定分析控制器:```typescript

复制代码
// 启用AI分析器
(context: CanvasRenderingContext2D | DrawingRenderingContext, imageAIOptions: ImageAIOptions): CanvasAttribute

// 搭配StartImageAnalyzer和StopImageAnalyzer使用

```

总结

HarmonyOS中的Canvas为开发者提供了强大的自定义绘制能力。通过本文的介绍,你应该已经掌握了:

  1. Canvas的基本概念和两种绘制上下文的使用

  2. 基本图形和文本的绘制方法

  3. 高级绘制技巧如模式填充、贝塞尔曲线和像素级操作

  4. 性能优化策略和实战案例

Canvas在鸿蒙生态中扮演着重要角色,特别是在数据可视化、游戏开发、自定义UI组件等场景中。随着鸿蒙系统的持续演进,Canvas的功能和性能还将进一步提升,为开发者创造更丰富的可能性。

https://developer.huawei.com/consumer/cn/training/classDetail/fd34ff9286174e848d34cde7f512ce22?type=1%3Fha_source%3Dhmosclass&ha_sourceId=89000248

相关推荐
北风江畔(LuckyClover)4 小时前
手戳一个HarmonyOS (鸿蒙)移动应用
华为·harmonyos
SWUT胖虎15 小时前
AlphabetIndexer组件 与 List 联动总结
list·harmonyos·arkts·鸿蒙
鸿蒙小白龙17 小时前
OpenHarmony轻量级内核LiteOS-M技术详解与应用实践
harmonyos·鸿蒙·鸿蒙系统·open harmony
Damon小智18 小时前
HarmonyOS应用开发-低代码开发登录页面(超详细)
低代码·harmonyos·鸿蒙·登录·arcts·arcui·griditem
爱笑的眼睛1120 小时前
深入探讨HarmonyOS中ListItem的滑动操作:从基础实现到高级分布式交互
华为·harmonyos
摘星编程21 小时前
【参赛心得】HarmonyOS创新赛获奖秘籍:如何用Stage模型和声明式UI打造高分作品
ui·华为·harmonyos·鸿蒙开发·stage模型
2501_919749031 天前
flutter鸿蒙:实现类似B站或抖音的弹幕功能
flutter·华为·harmonyos
鸿蒙小白龙1 天前
OpenHarmony后台服务开发指南:ServiceAbility与ServiceExtensionAbility全解析
harmonyos·鸿蒙系统·open harmony
浅蓝色1 天前
flutter平台判断,这次应该没问题了。支持鸿蒙,插件已发布
flutter·harmonyos