前言
代码运行环境:全部基于HarmonyOs NEXT
DevEco Studio:Build Version: 5.0.3.900
API:12
modelVersion:5.0.0
本篇文章,主要是使用Canvas绘制一个简单的画板,可以更改颜色,画笔粗细以及删除操作,主要运用到了CanvasRenderingContext2D中的绘制路径功能,我们可以看下基本实现的效果。
若在一个画板上进行随意的绘制,少不了画布的存在,鸿蒙当中为我们提供了Canvas组件,使用它,我们可以在上面进行绘制各种想要的图形,共有两个构造参数,可以只接收一个context参数,主要用于设置绘制的能力,除了context参数,也可以接收一个ImageAIOptions参数,主要用于需要AI分析选项的时候,一般传递一个参数就可以。
(context?: CanvasRenderingContext2D | DrawingRenderingContext): CanvasAttribute
CanvasRenderingContext2D比DrawingRenderingContext功能设置更加丰富,而且兼容其自身所带的功能,所以,在绘制元素上,还是建议使用CanvasRenderingContext2D。
设置画布
Canvas是一个组件,我们之间可以像其他组件一样进行使用。
Canvas(this.context)
.width('100%')
.height('100%')
传递的是一个CanvasRenderingContext2D对象。
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
RenderingContextSettings是用来配置CanvasRenderingContext2D对象的参数,可以设置是否开启抗锯齿。
路径绘制
路径绘制,包括了手指按下的开始路径,移动路径到指定点,以及手指移动时的点到指定点的路径连接,还有最后的路径结束,这样的流程,才能让线条绘制的更加丝滑,更加符合正常的使用。
.onTouch((event: TouchEvent) => {
switch (event.type) {
case TouchType.Down://
let downTouch = event.touches[0]
this.context.beginPath()
this.context.moveTo(downTouch.x, downTouch.y)
break
case TouchType.Move:
let touch = event.touches[0]
this.context.lineTo(touch.x, touch.y)
this.context.stroke()
break
case TouchType.Up:
this.context.closePath()
break
}
})
设置抗锯齿
通过设置抗锯齿,可以去掉线条的毛边,让线条变得丝滑顺畅。
Canvas(this.context)
.width('100%')
.height('100%')
.onReady(() => {
this.settings.antialias = true//打开抗锯齿
this.context.lineCap = "round"//设置指定线端点的样式,圆形
})
清除操作
this.context.clearRect(0, 0, this.context.width, this.context.height)
完整代码
@Entry
@Component
struct Index {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private mColors: string[] =
["#000000", "#ffffff", "#FF050C", "#FF7F1D", "#FFE613", "#B2FF29", "#31FFCA", "#2253FF", "#DA25FF", "#FFA687",
"#ACFFD3", "#98C8FF",
"#B8ACFF", "#FFCFC5", "#FFDF91"]
@State showListColor: boolean = true
@State sliderProgress: string = ""
build() {
Column() {
Canvas(this.context)
.width('100%')
.height('100%')
.onReady(() => {
this.settings.antialias = true
this.context.lineCap = "round"
})
.onTouch((event: TouchEvent) => {
switch (event.type) {
case TouchType.Down:
let downTouch = event.touches[0]
this.context.beginPath()
this.context.moveTo(downTouch.x, downTouch.y)
break
case TouchType.Move:
let touch = event.touches[0]
this.context.lineTo(touch.x, touch.y)
this.context.stroke()
break
case TouchType.Up:
this.context.closePath()
break
}
})
.layoutWeight(1)
//颜色
List({ space: 10 }) {
ForEach(this.mColors, (item: string, _: number) => {
ListItem() {
Text()
.width(20)
.height(20)
.backgroundColor(item)
.borderRadius(20)
.border({ width: 1, color: "#e8e8e8" })
.onClick(() => {
this.context.strokeStyle = item
})
}
})
}
.width("100%")
.height(40)
.listDirection(Axis.Horizontal)
.scrollBar(BarState.Off)
.alignListItem(ListItemAlign.Center)
.border({ width: { top: 1 }, color: "#e8e8e8" })
.visibility(this.showListColor ? Visibility.Visible : Visibility.Hidden)
Slider({
value: 0,
min: 0,
max: 50,
style: SliderStyle.OutSet
})
.showTips(true, this.sliderProgress)
.trackThickness(5)
.onChange((value: number, _: SliderChangeMode) => {
this.sliderProgress = value.toString()
this.context.lineWidth = value
})
Row() {
Image($r("app.media.canvas_del"))
.width(30)
.height(30)
.borderRadius(30)
.border({ width: 1, color: "#e8e8e8" })
.padding(5)
.onClick(() => {
//橡皮擦
this.context.strokeStyle = "#ffffff"
})
Image($r("app.media.canvas_clear"))
.width(30)
.height(30)
.borderRadius(30)
.border({ width: 1, color: "#e8e8e8" })
.margin({ left: 20 })
.padding(5)
.onClick(() => {
//清空
this.context.clearRect(0, 0, this.context.width, this.context.height)
})
}.width("100%")
.height(50)
.border({ width: { top: 1 }, color: "#e8e8e8" })
.justifyContent(FlexAlign.Center)
}
}
}
相关总结
画板,最重要的就是绘制,保证线条绘制的连续性,这一点很重要,还有就是beginPath方法一定要调用,否则更改颜色以及绘制就会出现不连续以及颜色设置错误问题。