共计 7908 个字符,预计需要花费 20 分钟才能阅读完成。
简介
ArkUI 是一套 UI 开发框架,提供了开发者进行利用 UI 开发时所需具备的能力。随着 OpenAtom OpenHarmony(以下简称“OpenHarmony”)不断更新迭代,ArkUI 也提供了很多新的组件,例如 Canvas、OffscreenCanvas、XComponent 组件等。新增的性能能够帮忙开发者开发出更晦涩、更好看的利用。本篇文章将为大家分享如何通过 Canvas 组件实现涂鸦性能,用户能够抉择空白画布或者简笔图进行自在绘画。
成果展现
以下为效果图:
首页显示了涂鸦的图片以及最初一张空白图片,在点击图片进入涂鸦页面后,能够对画笔的色彩、粗细进行设置。如果涂鸦过程中有谬误,能够用橡皮擦将画面擦除,也可点击革除按钮,清空涂鸦的内容,从新进行涂鸦操作。相干代码曾经上传至 SIG 仓库,链接如下:https://gitee.com/openharmony…
目录构造
源码剖析
一、Canvas 组件介绍
本篇样例次要利用 ArkUI 的 Canvas 组件实现涂鸦的性能,首先介绍一下 Canvas 组件。Canvas 组件次要蕴含了 Canvas 和 CanvasRenderingContext2D,Canvas 提供了画布性能,CanvasRenderingContext2D 提供了绘画的属性和办法。通过 CanvasRenderingContext2D 能够批改画笔的样色、粗细等属性,从而画出各式各样的图形。以下是 Canvas 和 CanvasRenderingContext2D 在样例开发中应用的相干接口信息。
CanvasRenderingContext2D
二、剖析源码页面布局
第一个模块是首页布局,首页显示所有涂鸦蕴含的图片,点击图片能够进入页面;第二个模块是涂鸦模块,能够设置画笔的色彩、边条宽度等。
- 首页布局
Column() {Text('抉择涂鸦的图片:').margin('10vp').fontSize('30fp').fontColor(Color.Blue).height('5%')
Grid() {ForEach(this.images, (item, index) => {GridItem() {Image(this.images[index])
.onClick((event) => {
router.push(
{
url: "pages/detailPage",
params: {imgSrc: this.images[index],
},
}
)
})
.width('100%')
.height('100%')
.objectFit(ImageFit.Contain)
}
})
}
.padding({left: this.columnSpace, right: this.columnSpace})
.columnsTemplate("1fr 1fr 1fr") // Grid 宽度均分成 3 份
.rowsTemplate("1fr 1fr") // Grid 高度均分成 2 份
.rowsGap(this.rowSpace) // 设置行间距
.columnsGap(this.columnSpace) // 设置列间距
.width('100%')
.height('95%')
}
.backgroundColor(Color.Pink)
- 涂鸦页面 – 画布 Canvas 的布局通过 Stack 组件进行包裹,并将 Canvas 画布笼罩在抉择的背景图片之上,这些背景图片次要是水果简笔画。
Stack() {Image(this.imgSrc).width('100%').height('100%').objectFit(ImageFit.Contain)
Canvas(this.context)
.width('100%')
.height('100%')
// .backgroundColor('#00ffff00')
.onReady(() => {})
.onTouch((event) => {if (event.type === TouchType.Down) {
this.eventType = 'Down';
this.drawing = true;
[this.x, this.y] = [event.touches[0].x, event.touches[0].y];
this.context.beginPath();
this.context.lineCap = 'round';
if (this.isEraserMode) {
// 橡皮擦模式
this.context.clearRect(this.x, this.y, 20, 20);
}
console.log('gyf Down');
}
if (event.type === TouchType.Up) {
this.eventType = 'Up';
this.drawing = false;
console.log('gyf Up!');
this.context.closePath();}
if (event.type === TouchType.Move) {if (!this.drawing) return;
this.eventType = 'Move';
console.log('gyf Move');
if (this.isEraserMode) {
// 橡皮擦模式
this.context.clearRect(event.touches[0].x, event.touches[0].y, 20, 20);
} else {
this.context.lineWidth = this.lineWidth;
this.context.strokeStyle = this.color;
this.context.moveTo(this.x, this.y);
this.x = event.touches[0].x;
this.y = event.touches[0].y;
this.context.lineTo(this.x, this.y);
this.context.stroke();}
}
})
}.width('100%').height('75%')
3. 涂鸦页面 – 画笔设置区域的布局
Column() {Row() {Text('粗细:')
Button('小').onClick(() => {
// 设置画笔的宽度
this.lineWidth = 5;
this.context.lineWidth = this.lineWidth;
this.isEraserMode = false;
console.log('gyf small button');
}).margin($r('app.float.wh_value_10'))
Button('中').onClick(() => {
// 设置画笔的宽度
this.lineWidth = 15;
this.context.lineWidth = this.lineWidth;
this.isEraserMode = false;
console.log('gyf middle button');
}).margin($r('app.float.wh_value_10'))
Button('大').onClick(() => {
// 设置画笔的宽度
this.lineWidth = 25;
this.context.lineWidth = this.lineWidth;
this.isEraserMode = false;
console.log('gyf big button');
}).margin($r('app.float.wh_value_10'))
Button('超大').onClick(() => {
// 设置画笔的宽度
this.lineWidth = 40;
this.context.lineWidth = this.lineWidth;
this.isEraserMode = false;
console.log('gyf super big button');
})
}.padding($r('app.float.wh_value_10')).margin($r('app.float.wh_value_5'))
// 画笔色彩
Scroll() {Row() {Text('色彩:')
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 彩色
this.color = '#000000';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
console.log('gyf black button');
})
.backgroundColor('#000000')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 红色
this.color = '#FF0000';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
console.log('gyf red button');
})
.backgroundColor('#FF0000')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 绿色
this.color = '#00FF00';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
console.log('gyf green button');
})
.backgroundColor('#00FF00')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 蓝色
this.color = '#0000FF';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#0000FF')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 棕色
this.color = '#A52A2A';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#A52A2A')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 紫色
this.color = '#800080';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#800080')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 紫红色
this.color = '#FF00FF';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#FF00FF')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 深蓝色
this.color = '#00008B';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#00008B')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 深天蓝
this.color = '#00BFFF';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#00BFFF')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 绿色
this.color = '#008000';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#008000')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 青绿色
this.color = '#32CD32';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#32CD32')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 橙色
this.color = '#FFA500';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#FFA500')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
Button(' ', { type: ButtonType.Circle})
.onClick(() => {
// 黄色
this.color = '#FFFF00';
this.context.strokeStyle = this.color;
this.isEraserMode = false;
})
.backgroundColor('#FFFF00')
.width('40vp')
.width('40vp')
.margin($r('app.float.wh_value_10'))
}.padding('10vp')
}
.scrollable(ScrollDirection.Horizontal) // 设置滚动条程度方向滚动
.margin($r('app.float.wh_value_5'))
Row() {Image('/common/images/eraser.png')
.onClick(() => {
// 橡皮擦模式
this.isEraserMode = true;
console.log('gyf eraser button');
})
.width('50vp')
.height('50vp')
.margin('10vp')
Button('清理画板').onClick(() => {this.context.clearRect(0, 0, 1000, 1000);
})
}
.margin($r('app.float.wh_value_5'))
}
.width('100%')
.height('25%')
.alignItems(HorizontalAlign.Start)
三、逻辑代码
逻辑代码存在于 Canvas 的 onTouch 事件中,通过 TouchType 的 Down、Up、Move 来判断开始、挪动和完结的动作。一笔残缺的绘制蕴含一次 Down 和 Up,其中有若干次的 Move。橡皮擦模式通过 clearRect 接口实现擦除的性能。
.onTouch((event) => {if (event.type === TouchType.Down) {
this.eventType = 'Down';
this.drawing = true;
[this.x, this.y] = [event.touches[0].x, event.touches[0].y];
this.context.beginPath();
this.context.lineCap = 'round';
if (this.isEraserMode) {
// 橡皮擦模式
this.context.clearRect(this.x, this.y, 20, 20);
}
console.log('gyf Down');
}
if (event.type === TouchType.Up) {
this.eventType = 'Up';
this.drawing = false;
console.log('gyf Up!');
this.context.closePath();}
if (event.type === TouchType.Move) {if (!this.drawing) return;
this.eventType = 'Move';
console.log('gyf Move');
if (this.isEraserMode) {
// 橡皮擦模式
this.context.clearRect(event.touches[0].x, event.touches[0].y, 20, 20);
} else {
this.context.lineWidth = this.lineWidth;
this.context.strokeStyle = this.color;
this.context.moveTo(this.x, this.y);
this.x = event.touches[0].x;
this.y = event.touches[0].y;
this.context.lineTo(this.x, this.y);
this.context.stroke();}
}
})
总结
本文介绍了如何应用 ArkUI 框架提供的 Canvas 组件实现涂鸦性能。首先,通过 Canvas 的 onTouch 事件来跟踪 Down、Move 和 Up 的事件,再设置 CanvasRenderingContext2D 的相干属性并调用相干的办法,最终实现涂鸦的性能。除了文中分享的涂鸦样例,开发者还能够通过拓展其余相干的属性和办法,实现更多好玩的、高性能的样例。