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为开发者提供了强大的自定义绘制能力。通过本文的介绍,你应该已经掌握了:
-
Canvas的基本概念和两种绘制上下文的使用
-
基本图形和文本的绘制方法
-
高级绘制技巧如模式填充、贝塞尔曲线和像素级操作
-
性能优化策略和实战案例
Canvas在鸿蒙生态中扮演着重要角色,特别是在数据可视化、游戏开发、自定义UI组件等场景中。随着鸿蒙系统的持续演进,Canvas的功能和性能还将进一步提升,为开发者创造更丰富的可能性。