头图

鸿蒙元服务实战-笑笑五子棋(2)

章节导读

本章节主要讲解如何创建元服务和使用 canvas 描绘图形

目标

img

上一章最后讲到了 笑笑五子棋 主要的技术栈如下:

  1. ArkTS API 12
  2. Canvas
  3. 元服务独有的 AtomicServiceTabs
  4. 卡片开发
  5. 元服务的创建
  6. 元服务的上架

那么本章节就开始实现这个案例。

AGC 平台上创建元服务

需要先在AGC平台上项目,然后再新建元服务。_一个项目可以对应多个元服务。_

image-20250104215412454

DevEco Studio 创建元服务工程

AGC 平台上创建好了项目,我们可以在本地创建元服务。

  1. 新建元服务

image-20250104215538468


  1. 选择 笑笑五子棋

image-20250104215654355

  1. 选择工程位置

image-20250104215718600

  1. 元服务创建成功

    image-20250104220153486

Canvas 入门

Canvas提供画布组件,用于自定义绘制图形,开发者使用 CanvasRenderingContext2D 对象和 OffscreenCanvasRenderingContext2D

对象在 Canvas 组件上进行绘制,绘制对象可以是基础形状、文本、图片等。

基本使用

canvas 的基本使用分为 4 步:

  1. 设置是否抗锯齿抗锯齿(Anti - aliasing)是一种在数字图形处理中使用的技术,主要用于减少图像中因为像素有限而产生的锯齿状边缘的现象
  2. 创建画布上下文
  3. 渲染画布组件
  4. 在画布上描绘图案
@Entry
@Component
struct Index {
  // 1 用来配置CanvasRenderingContext2D对象的参数,包括是否开启抗锯齿,true表明开启抗锯齿。
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  // 2 用来创建CanvasRenderingContext2D对象,通过在canvas中调用CanvasRenderingContext2D对象来绘制。
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  build() {
      // 3 在canvas中调用CanvasRenderingContext2D对象。
    Column(){
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#F5DC62')
        .onReady(() => {
          // 4 可以在这里绘制内容。
          this.context.strokeRect(50, 50, 200, 150);
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}
  1. 效果

image-20250104222001043

canvas 常见用法

canvas 的核心思想是将想要的图形如,直线、圆圈、矩形等图形描绘到画布上。如果想要呈现出比较酷炫的效果,做法是:

  1. 描绘图形
  2. 擦除画布
  3. 计算数值-重新描绘图形
  4. 擦除画布
  5. 。。。

通过以上过程实现动画效果

image-20250104223622772

canvas 的坐标系

在 canvas 中画图形都是基于坐标系来进行的。 左上角为起点。

image-20250104224722034

描绘图形

canvas 中内置的常见的描绘图形的方法有以下:

  1. 直线
  2. 矩形
  3. 弧形
  4. 文本
  5. 图像
  6. ...

直线

描绘直线可以使用:

  1. 定起点 moveTo
  2. 定终点 lineTo
  3. 开始描绘 stroke
this.context.moveTo(10, 10);
this.context.lineTo(100, 100);
this.context.stroke();

image-20250104224216771

矩形

可以使用直线lineTo自己画成一个矩形。也可以直接使用 strokeRect直接生成矩形

lineTo 画矩形

this.context.moveTo(10, 10);
this.context.lineTo(300, 10);
this.context.lineTo(300, 300);
this.context.lineTo(10, 300);
//   自动闭环
this.context.closePath();
//   开始描述 将路径的当前点移回到路径的起点,当前点到起点间画一条直线
this.context.stroke();

image-20250104225516822

strokeRect 画矩形

// this.context.strokeRect(x, y, 宽度, 高度);
this.context.strokeRect(50, 50, 200, 150);

image-20250104225643875

弧形

弧形可以使用 arcarcTo 来描绘

arc

arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean)
参数名类型必填说明
xnumber弧线圆心的 x 坐标值。默认单位:vp。
ynumber弧线圆心的 y 坐标值。默认单位:vp。
radiusnumber弧线的圆半径。默认单位:vp。
startAnglenumber弧线的起始弧度。单位:弧度
endAnglenumber弧线的终止弧度。单位:弧度
counterclockwiseboolean是否逆时针绘制圆弧。true:逆时针方向绘制椭圆。false:顺时针方向绘制椭圆。默认值:false。

这里需要注意的是 arc 使用的单位是弧度不是角度

一圈 = 360角度 =  2 * Math.PI
半圈 = 180角度 =  Math.PI ≈ 3.14

观察以下效果

image-20250104230514600

100,75 是圆心坐标

50 是半径

0 是开始的弧度

6.28 ≈ 2 * Math.PI = 一圈


arc 是从正右方向开始旋转的。

this.context.beginPath();
this.context.arc(100, 75, 50, 0, 3.14 / 2);
this.context.stroke();

image-20250104230945457

arcTo

arcTo(x1: number, y1: number, x2: number, y2: number, radius: number)
参数名类型必填说明
x1number第一个控制点的 x 坐标值。默认单位:vp。
y1number第一个控制点的 y 坐标值。默认单位:vp。
x2number第二个控制点的 x 坐标值。默认单位:vp。
y2number第二个控制点的 y 坐标值。默认单位:vp。
radiusnumber圆弧的圆半径值。默认单位:vp。

image-20250104235451185

this.context.beginPath();
this.context.strokeStyle = "#000000";
this.context.lineWidth = 3;
this.context.moveTo(360, 20);
this.context.arcTo(360, 170, 110, 170, 150);
this.context.stroke();

辅助理解

想象一下,我们有一个起点(即当前路径的最后一个点),然后有三个更多的点:两个控制点 (x1, y1) 和 (x2, y2),以及由 radius

定义的一个圆心。arcTo 会创建一条从起点到第二个控制点 (x2, y2) 的圆弧,这条圆弧是位于以 radius 为半径的圆周上的一部

分。该圆弧会在起点和第一个控制点 (x1, y1) 之间形成一个切线,并且也会在第二个控制点 (x2, y2) 和圆弧的终点之间形成一个切线。

image-20250104234845265

文本

  1. strokeText表示描边的图形
  2. fillText 表示填充的图形,还有其他fillfillRect等也表示填充。

strokeText

  this.context.font = '55px sans-serif'
  this.context.strokeText("Hello World!", 20, 60)

image-20250104235533508

fillText

this.context.font = '55px sans-serif'
this.context.fillText("Hello World!", 20, 60)

image-20250104235642059

图像

drawImage可以把图像描绘到画布上,很多的在线图形合成效果都可以利用该功能实现

drawImage(image: ImageBitmap | PixelMap, dx: number, dy: number): void

drawImage(image: ImageBitmap | PixelMap, dx: number, dy: number, dw: number, dh: number): void

drawImage(image: ImageBitmap | PixelMap, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void

参数名类型必填说明
imageImageBitmapPixelMap图片资源,请参考 ImageBitmap 或 PixelMap。
sxnumber裁切源图像时距离源图像左上角的 x 坐标值。image 类型为 ImageBitmap 时,默认单位:vp。image 类型为 PixelMap 时,单位:px。
synumber裁切源图像时距离源图像左上角的 y 坐标值。image 类型为 ImageBitmap 时,默认单位:vp。image 类型为 PixelMap 时,单位:px。
swnumber裁切源图像时需要裁切的宽度。image 类型为 ImageBitmap 时,默认单位:vp。image 类型为 PixelMap 时,单位:px。
shnumber裁切源图像时需要裁切的高度。image 类型为 ImageBitmap 时,默认单位:vp。image 类型为 PixelMap 时,单位:px。
dxnumber绘制区域左上角在 x 轴的位置。默认单位:vp。
dynumber绘制区域左上角在 y 轴的位置。默认单位:vp。
dwnumber绘制区域的宽度。当绘制区域的宽度和裁剪图像的宽度不一致时,将图像宽度拉伸或压缩为绘制区域的宽度。默认单位:vp。
dhnumber绘制区域的高度。当绘制区域的高度和裁剪图像的高度不一致时,将图像高度拉伸或压缩为绘制区域的高度。默认单位:vp。

@Entry
@Component
struct Index {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private img: ImageBitmap = new ImageBitmap("/images/example.jpg")

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor('#ffff00')
        .onReady(() => {
          this.context.drawImage(this.img, 0, 0)
          this.context.drawImage(this.img, 0, 150, 300, 100)
          this.context.drawImage(this.img, 0, 0, 500, 500, 0, 300, 400, 200)
        })
    }
    .width('100%')
    .height('100%')
  }
}

image-20250105000141244

canvas 浅尝动态效果 1

const width = px2vp(display.getDefaultDisplaySync().availableWidth) * 0.9;
const height = width;
let x = 0;
let y = 0;
setInterval(() => {
  this.context.strokeRect(x, y, 100, 100);
  x++;
  y++;
}, 20);

PixPin_2025-01-05_00-07-08

canvas 浅尝动态效果 2

const width = px2vp(display.getDefaultDisplaySync().availableWidth) * 0.9;
const height = width;
let x = 0;
let y = 0;
setInterval(() => {
  // 清理画布
  this.context.strokeRect(x, y, 100, 100);
  x++;
  y++;
}, 20);

PixPin_2025-01-05_00-08-20

canvas 属性 一览

名称说明
fillStyle设置绘制的填充色,支持多种类型及对应创建方式,有默认值。
lineWidth设置绘制线条的宽度,有默认值及取值限制。
strokeStyle设置线条的颜色,支持多种类型及对应创建方式,有默认值。
lineCap指定线端点的样式,有可选值及默认值。
lineJoin指定线段间相交的交点样式,有可选值及默认值。
miterLimit设置斜接面限制值,有默认值及取值限制。
font设置文本绘制中的字体样式,包含多种可选参数及默认值。
textAlign设置文本绘制中的文本对齐方式,有可选值及默认值。
textBaseline设置文本绘制中的水平对齐方式,有可选值及默认值。
globalAlpha设置透明度,有默认值。
lineDashOffset设置画布的虚线偏移量,有默认值。
globalCompositeOperation设置合成操作的方式,有可选值及默认值。
shadowBlur设置绘制阴影时的模糊级别,有默认值及取值限制。
shadowColor设置绘制阴影时的阴影颜色,有默认值。
shadowOffsetX设置绘制阴影时和原有对象的水平偏移值,有默认值。
shadowOffsetY设置绘制阴影时和原有对象的垂直偏移值,有默认值。
imageSmoothingEnabled设置绘制图片时是否进行图像平滑度调整,有默认值。
height表示组件高度,有默认单位。
width表示组件宽度,有默认单位。
imageSmoothingQuality设置图像平滑度,有默认值。
direction设置绘制文字时使用的文字方向,有默认值。
filter设置图像的滤镜,支持多种滤镜效果,有默认值。
canvas获取和 CanvasRenderingContext2D 关联的 Canvas 组件的 FrameNode 实例,
可监听可见状态,默认值为 null。

canvas 方法 一览

名称说明
fillRect推测用于进行图形填充相关操作(通常是填充矩形区域)
strokeRect推测用于绘制矩形边框相关操作(通常是绘制矩形的轮廓)
clearRect推测用于清除指定矩形区域的内容
fillText推测用于对文本进行填充操作(比如设置文本填充颜色等相关样式填充)
strokeText推测用于绘制文本的轮廓相关操作
measureText推测用于测量文本相关的尺寸等属性
stroke一般用于绘制图形的轮廓、线条等(按常规语义理解)
beginPath通常用于开始定义一个新的路径,后续可基于此路径进行图形绘制等操作
moveTo常用来将画笔移动到指定坐标位置,作为绘制路径的起始点等操作
lineTo一般用于从当前画笔位置绘制直线到指定坐标位置,构建路径内容
closePath通常用于闭合当前正在绘制的路径,使路径形成封闭图形
createPattern可能用于创建某种图案(比如重复平铺的图案等)用于绘制等
bezierCurveTo大概率用于绘制贝塞尔曲线,通过控制点来定义曲线形状
quadraticCurveTo推测用于绘制二次贝塞尔曲线,指定控制点来确定曲线走向
arc一般用于绘制圆弧,通过圆心、半径、起始角度、结束角度等参数来定义
arcTo常用来绘制与两条切线相切的圆弧,按给定条件确定圆弧形状
ellipse用于绘制椭圆图形,需指定相关参数如圆心坐标、长半轴、短半轴等
rect可用于绘制矩形,指定矩形的左上角坐标、宽度、高度等参数
fill用于对已绘制的图形或者指定区域进行填充操作
clip可能用于设置裁剪区域,后续绘制内容只在裁剪区域内显示
reset12+从名称看可能是在特定版本(12+)中用于重置某些状态或设置的操作
saveLayer12+在特定版本(12+)里可能用于保存图层相关状态等操作
restoreLayer12+在特定版本(12+)里对应于之前保存图层状态进行恢复的操作
resetTransform推测用于重置图形变换相关的设置(比如旋转、缩放等变换)
rotate用于将图形进行旋转操作,需指定旋转角度等参数
scale用于对图形进行缩放操作,指定横向和纵向的缩放比例
transform一般用于对图形进行多种变换(如平移、旋转、缩放等组合变换)的设置
setTransform可能用于设置图形的变换矩阵,来确定图形的变换情况
getTransform推测用于获取当前图形的变换相关信息(比如变换矩阵等)
translate用于将图形进行平移操作,指定在横、纵坐标方向平移的距离
drawImage通常用于在画布上绘制图像,指定图像源及绘制位置等参数
createImageData可能用于创建图像数据对象(比如像素数据等相关内容)
getPixelMap推测用于获取像素映射相关的数据(比如图像像素的分布等情况)
setPixelMap大概是用于设置像素映射相关数据,改变图像像素表现等
getImageData一般用于获取图像的像素数据等具体信息内容
putImageData通常是将获取到的图像数据(如像素数据)重新应用到画布等位置
setLineDash可能用于设置线条的虚线样式,指定虚线的长度、间隔等参数
getLineDash推测用于获取当前线条所设置的虚线样式相关参数
transferFromImageBitmap从名称看可能是与从图像位图进行数据转移相关操作
toDataURL通常用于将画布等内容转换为可以表示图像数据的 URL 格式
restore一般用于恢复之前保存的某些状态(如画布状态等)
save常用来保存当前画布等相关的状态,以便后续恢复使用
createLinearGradient用于创建线性渐变对象,可用于图形的渐变填充等操作
createRadialGradient用于创建径向渐变对象,定义从中心向外扩散的渐变效果
createConicGradient用于创建圆锥渐变对象,实现类似圆锥形状的渐变效果

总结

这篇文章主要是介绍了元服务的创建和基本 canvas 的使用

如果你兴趣想要了解更多的鸿蒙应用开发细节和最新资讯,欢迎在评论区留言或者私信或者看我个人信息,可以加入技术交流群。


万少
66 声望5 粉丝