鸿蒙小案例-你画我猜
1.准备组件(组件布局)
2.实现跟随鼠标画笔画出图案功能
3.实现复制上面的画笔的图案功能
4.其他小功能
1.组件的准备
画布的组件官方给的API是Canvas,需要传递一个参数CanvasRenderingContext2D
直接搜索API 使用官方案例
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#ffff00')
.onReady(() => {
this.context.fillRect(0, 30, 100, 100)
})
}
.width('100%')
.height('100%')
因为我们参数描述到
不支持多个Canvas共用一个CanvasRenderingContext2D对象
所以,结合我们的显示区域,基础代码精简为
@Entry
@Preview
@Component
struct Nihuawocai2 {
private context01: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))
private context02: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))
/**
* 1.准备组件(画布布局)
* 2.实现跟随鼠标画笔画出图案
* 3.实现复制上面的画笔的图案
* 4.其他小功能
*/
build() {
Row() {
Column() {
//自己绘画的区域
Row(){
Canvas(this.context01)
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.onReady(() => {
//this.context01.fillRect(0, 30, 100, 100)
})
}.height('40%').border({ width: { bottom:5 },color:Color.Red })
//复制绘画的区域
Row(){
Canvas(this.context02)
.width('100%')
.height('100%')
.backgroundColor(Color.Grey)
.onReady(() => {
//this.context02.fillRect(0, 30, 100, 100)
})
}.height('40%')
//功能区
Row(){
Button("清屏")
.onClick(() =>
{
})
}.height('20%')
}.width('100%')
}.height('100%')
}
}
实现效果:
2.实现跟随鼠标画笔画出图案
画笔呢肯定是需要用到触摸事件,API如下
所以Canvas增加onTouch事件
Canvas(this.context01)
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.onTouch((event: TouchEvent) =>{
})
当触摸事件是按下时,开始绘画
所以onTouch增加代码
.onTouch((event: TouchEvent) =>{
//按下时触发,开始绘画
if (event.type === TouchType.Down)
{
AlertDialog.show({message:'按下手指'})
}
//抬起时触发 结束绘画
if (event.type === TouchType.Up)
{
AlertDialog.show({message:'抬起手指'})
}
//移动时触发 正在绘画
if (event.type === TouchType.Move)
{
AlertDialog.show({message:'移动手指'})
}
})
预览器测试一下,发现 移动手指会一直显示,说明这个触发是没问题的
接下来首先理一下绘画的思路
按下时,准备绘画,从按下的坐标点开始
移动时,正在绘画,随着移动的轨迹,不停记录坐标点,链接上一个坐标点到新坐标点
抬起时,结束绘画,记录当前坐标点为结束点
可能会有多次按下,抬起的操作
所以,我们需要增加一个坐标类,再给一个是否起始点的布尔值
//坐标对象
class zbClass{
x:number = 0
y:number = 0
//按下时记录true,移动时不记录,抬起时记录false
isStart?:boolean = false
}
增加常量:
是否开始绘画,用来区分多次按下的操作
坐标集合,用来记录绘画轨迹坐标点
//是否开始绘画
isDraw:boolean = false
//坐标点 集合
zbList: zbClass[] = []
按下时,记录当前坐标,并增加当前坐标到坐标集合中
//按下时触发,开始绘画
if (event.type === TouchType.Down)
{
this.isDraw = true
this.context01X = event.touches[0].x
this.context01Y = event.touches[0].y
this.zbList.push({
x:this.context01X,
y:this.context01Y,
isStart:true
})
//开始绘画
this.context01.beginPath()
}
开始绘画,参考CanvasRenderingContext2D API官方案例,既将画笔从一个点连接到另一个点,然后不停循环
将绘画写成一个方法,直接去调用
//移动时触发 正在绘画
if (event.type === TouchType.Move)
{
if (this.isDraw)
{
//绘画中
this.drawIng(event.touches[0].x, event.touches[0].y)
}
}
drawIng方法
//绘画过程
drawIng(x: number, y: number)
{
//先移动画笔到起始点
this.context01.moveTo(this.context01X,this.context01Y)
//设置绘画边框宽度
this.context01.lineWidth = 5
//将画笔从上一个坐标 链接到 手指移动到的新坐标
this.context01.lineTo(x,y)
//更新常量坐标点为手指移动坐标点,随着手指移动,形成循环
this.context01X = x
this.context01Y = y
//因为有复制操作,所以,需要保存坐标点
this.zbList.push({
x:x,
y:y
})
this.context01.stroke()
}
抬起手指操作
//抬起时触发 结束绘画
if (event.type === TouchType.Up)
{
//当前按下手指周期,绘画结束
this.isDraw = false
//记录当前周期的结束坐标
this.zbList.push({
x: event.touches[0].x,
y: event.touches[0].y,
isStart:false
})
this.context01.closePath()
}
此时通过预览器测试一下,基本功能已经实现,而且抬起再按下也能继续绘画了
3.实现复制上面的画笔的图案
复制动作可以在全部绘画完后,统一复制,也可以在绘画的同时延迟复制
事后统一复制也就是将集合中的点全部连一遍,比较简单,所以我们边画边复制,在抬起一次手指时开始复制
增加常量:
//复制画,坐标点
context02X: number = 0
context02Y: number = 0
//定时器,用来循环
timer: number = -1
增加一个复制方法
//复制动作
cpDraw()
{
this.context02.lineWidth = 5
this.timer = setInterval(() =>
{
if (this.zbList.length === 0)
{
clearInterval(this.timer)
this.timer = -1
return
}
let p = this.zbList.shift()
if (p.isStart)
{
this.context02.closePath()
this.context02.beginPath()
this.context02X = p.x
this.context02Y = p.y
} else
{
//移动画笔
this.context02.moveTo(this.context02X, this.context02Y)
//链接点
this.context02.lineTo(p.x, p.y)
//更新点
this.context02X = p.x
this.context02Y = p.y
this.context02.stroke()
}
}, 100)
}
测试功能,一切OK
4.其他小功能
清理屏幕
将两个画布的坐标点全部都设置为初始点
Button("清屏")
.onClick(() =>
{
this.context01.clearRect(0, 0, 360, 300)
this.context02.clearRect(0, 0, 360, 300)
this.zbList = []
})
完整代码
@Entry
@Preview
@Component
struct Nihuawocai2 {
private context01: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))
private context02: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))
//第一个画布的坐标信息
context01X:number = 0
context01Y:number = 0
//是否开始绘画
isDraw:boolean = false
//坐标点 集合
zbList: zbClass[] = []
//下方绘画坐标点
context02X: number = 0
context02Y: number = 0
//定时器,用来循环
timer: number = -1
//绘画过程
drawIng(x: number, y: number)
{
//先移动画笔到起始点
this.context01.moveTo(this.context01X,this.context01Y)
//将画笔从上一个坐标 链接到 手指移动到的新坐标
this.context01.lineTo(x,y)
//更新常量坐标点为手指移动坐标点,随着手指移动,形成循环
this.context01X = x
this.context01Y = y
//因为有复制操作,所以,需要保存坐标点
this.zbList.push({
x:x,
y:y
})
this.context01.stroke()
}
//复制动作
cpDraw()
{
this.timer = setInterval(() =>
{
if (this.zbList.length === 0)
{
clearInterval(this.timer)
this.timer = -1
return
}
let p = this.zbList.shift()
if (p.isStart)
{
this.context02.closePath()
this.context02.beginPath()
this.context02X = p.x
this.context02Y = p.y
} else
{
//移动画笔
this.context02.moveTo(this.context02X, this.context02Y)
//链接点
this.context02.lineTo(p.x, p.y)
//更新点
this.context02X = p.x
this.context02Y = p.y
this.context02.stroke()
}
}, 100)
}
/**
* 1.准备组件(画布布局)
* 2.实现跟随鼠标画笔画出图案
* 3.实现复制上面的画笔的图案
* 4.其他小功能
*/
build() {
Row() {
Column() {
//自己绘画的区域
Row(){
Canvas(this.context01)
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.onTouch((event: TouchEvent) =>{
//按下时触发,开始绘画
if (event.type === TouchType.Down)
{
//当前按下手指周期,绘画开始
this.isDraw = true
this.context01X = event.touches[0].x
this.context01Y = event.touches[0].y
this.zbList.push({
x:this.context01X,
y:this.context01Y,
isStart:true
})
//开始绘画
this.context01.beginPath()
}
//抬起时触发 结束绘画
if (event.type === TouchType.Up)
{
//当前按下手指周期,绘画结束
this.isDraw = false
this.zbList.push({
x: event.touches[0].x,
y: event.touches[0].y,
isStart:false
})
this.context01.closePath()
this.cpDraw()
}
//移动时触发 正在绘画
if (event.type === TouchType.Move)
{
if (this.isDraw)
{
//绘画中
this.drawIng(event.touches[0].x, event.touches[0].y)
}
}
})
.onReady(() => {
//设置绘画边框宽度
this.context01.lineWidth = 5
})
}.height('40%').border({ width: { bottom:5 },color:Color.Red })
//复制绘画的区域
Row(){
Canvas(this.context02)
.width('100%')
.height('100%')
.backgroundColor(Color.Grey)
.onReady(() => {
//设置绘画边框宽度
this.context02.lineWidth = 5
})
}.height('40%')
//功能区
Row(){
Button("清屏")
.onClick(() =>
{
this.context01.clearRect(0, 0, 360, 300)
this.context02.clearRect(0, 0, 360, 300)
this.zbList = []
})
}.height('20%')
}.width('100%')
}.height('100%')
}
}
//坐标对象
class zbClass{
x:number = 0
y:number = 0
//按下时记录true,移动时不记录,抬起时记录false
isStart?:boolean = false
}
使用模拟器测试功能OK
模拟器效果
— end