常规几何图形
鸿蒙有专门的绘制组件,如 Line,Rect,Circle,Ellipse,Path,Polyline,Polygon 等等,绘制组件可以用 Shape 作为父组件,实现类似 SVG 的效果,也能单独使用。
Line
Line 用于绘制一条线,如下所示:
ts
@Entry
@Component
struct Index {
build() {
Column() {
Line()
.width(200)
.height(200)
.startPoint([0, 0])
.endPoint([100, 100])
.stroke(Color.White)
.strokeLineCap(LineCapStyle.Round)
.strokeWidth(6)
.backgroundColor(Color.Red)
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
如果需要绘制虚线,可以使用 strokeDashArray 属性来设置线条间隙。
ts
@Entry
@Component
struct Index {
build() {
Column() {
Line()
.width(300)
.height(300)
.startPoint([0, 0])
.endPoint([300, 300])
.stroke(Color.White)
.strokeLineCap(LineCapStyle.Square)
.strokeWidth(3)
.antiAlias(true)//是否开启抗锯齿效果
.strokeDashArray([10, 10])//线条间隙
.strokeDashOffset(10)//线条绘制起点偏移量
.backgroundColor(Color.Red)
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
Rect
Rect 用于绘制矩形,如下所示:
ts
@Entry
@Component
struct Index {
build() {
Column() {
Rect()
.width(300)
.height(300)
.antiAlias(true)
.fill(Color.Pink)//填充色
.fillOpacity(0.5)//填充区透明度,取值0-1
.radius(20)//圆角半径
.stroke(Color.Gray)//边框颜色
.strokeOpacity(0.5)//边框透明度
.strokeWidth(2) //边框宽度
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
Circle
Circle 用于绘制圆形,如下所示:
ts
@Entry
@Component
struct Index {
build() {
Column() {
Circle()
.width(300)
.height(300)
.fill(Color.Orange)
.fillOpacity(0.3)
.strokeWidth(2)
.stroke(Color.Brown)
.strokeDashArray([10, 10])
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
Ellipse
Ellipse 用于绘制椭圆,如下所示:
ts
@Entry
@Component
struct Index {
build() {
Column() {
Ellipse()
.width(300)
.height(200)
.fill(Color.Transparent)
.strokeWidth(2)
.stroke(Color.Brown)
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
Path
Path 用于绘制路径,如下所示:
ts
@Entry
@Component
struct Index {
build() {
Column() {
Path()
.width('300px')
.height('300px')
.commands('M0 150 Q150 0 300 150 L150 300 Z')
.stroke(Color.White)
.strokeWidth(1)
.antiAlias(true)
.backgroundColor(Color.Red)
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
Commands 绘制命令如下:
- M:相当于 Android 中的 moveTo,参数是(x,y),在这个坐标点开始一个新的路径。
- L:相当于 Android 中的 lineTo,参数是(x,y), 从当前点到该坐标点画一条线,该坐标成为新的当前点。
- H:参数是 x,从当前点绘制绘制一条水平线。
- V:参数是 y,从当前点绘制一条垂直线。
- Q:参数是 (x1 y1 x y),(x1,y1) 为控制点,从当前点到 (x,y) 绘制二次贝塞尔曲线。
- T:参数是 (x y),从当前点到 (x,y) 绘制二次贝塞尔曲线。若前一个命令是Q或T,则控制点是上一个命令的终点控制点相对于起点的映射,如果没有前一个命令或前一个命令不是Q或T,则第一个控制点与当前点重合。
- C:参数是 (x1 y1 x2 y2 x y),使用 (x1,y1) 作为起点控制点,(x2,y2) 作为终点控制点,从当前点到 (x, y) 绘制三次贝塞尔曲线。
- S:参数是 (x2 y2 x y),(x2,y2)作为终点控制点,绘制从当前点到 (x,y) 绘制三次贝塞尔曲线。若前一个命令是C或S,则起点控制点是上一个命令的终点控制点相对于起点的映射,如果没有前一个命令或者前一个命令不是C或S,则第一个控制点与当前点重合。
- A:参数是 (rx ry x-axis-rotation large-arc-flag sweep-flag x y),rx 和 ry 分别表示椭圆弧所在椭圆的 x 轴半径和 y 轴半径。x-axis-rotation 表示椭圆的 x 轴相对于当前坐标轴的旋转角度,单位是度,如果为 0,则椭圆没有旋转。large-arc-flag 为 1,表示绘制大于 180 度的椭圆弧,为 0,表示绘制小于等于 180 度的椭圆弧。sweep-flag 为 1 表示顺时针绘制椭圆弧,为 0 表示逆时针绘制椭圆弧。
- Z:通过将当前路径连接回当前子路径的初始点来关闭当前子路径。
通过 A 命令绘制一个椭圆弧
ts
@Entry
@Component
struct Index {
build() {
Column() {
Path()
.width('300px')
.height('300px')
.commands('M0 150 A150 100 0 0 1 300 150 L150 300 Z')
.stroke(Color.White)
.strokeWidth(1)
.antiAlias(true)
.backgroundColor(Color.Red)
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
Polyline
Polyline 用于绘制折线,属性 points 可以设置折线经过坐标点的列表,如下所示:
ts
@Entry
@Component
struct Index {
build() {
Column() {
Polyline()
.width(300)
.height(300)
.points([[0, 0], [100, 80], [200, 40], [150, 150], [300, 300]])
.backgroundColor(Color.Red)
.stroke(Color.White)
.fill(Color.Transparent)
.antiAlias(true)
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
Polygon
Polygon 用于绘制多边形,属性 points 可以设置多边形的顶点坐标列表,如下所示:
ts
@Entry
@Component
struct Index {
build() {
Column() {
Polygon()
.width(300)
.height(300)
.points([[150, 0], [0, 150], [150, 300], [300, 150]])
.backgroundColor(Color.Red)
.stroke(Color.Yellow)
.fill(Color.Transparent)
.antiAlias(true)
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
}
自定义图形
我们可以使用 Canvas 来绘制自定义图形,在 Canvas 中可以调用 CanvasRenderingContext2D 对象来绘制图形。
ts
@Entry
@Component
struct Index {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
build() {
Column() {
Canvas(this.context).width('100%').height('100%').onReady(() => {
this.context.fillStyle = Color.Red
this.context.fillRect(100, 100, 100, 100)
this.context.strokeStyle = Color.White
this.context.lineWidth = 10
this.context.beginPath()
this.context.moveTo(100, 100)
this.context.lineTo(200, 200)
this.context.moveTo(200, 100)
this.context.lineTo(100, 200)
this.context.stroke()
})
}
.height('100%')
.width('100%')
}
}
效果如下:
常规的几何图形,也可以使用 CanvasRenderingContext2D 来绘制。
ts
@Entry
@Component
struct Index {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
build() {
Column() {
Canvas(this.context).width('100%').height('100%').onReady(() => {
this.context.fillStyle = Color.Orange
this.context.strokeStyle = Color.Black
this.context.lineWidth = 5
/**
* 绘制矩形
* 参数(矩形起点x坐标,矩形起点y坐标,矩形的长,矩形的宽)
*/
this.context.beginPath()
this.context.rect(100, 100, 100, 100)
this.context.stroke()
/**
* 绘制圆形
* 参数(圆心的x坐标,圆心的y坐标,圆弧半径,起始角度(弧度),结束角度(弧度),true逆时针绘制false顺时针)
*/
this.context.beginPath()
this.context.arc(150, 300, 50, 0, 2 * Math.PI, false)
this.context.fill()
/**
* 绘制椭圆
* 参数(椭圆中心x坐标,椭圆中心y坐标,水平半径,垂直半径,旋转角度(弧度),起始角度(弧度),结束角度(弧度),true逆时针绘制false顺时针)
*/
this.context.beginPath()
this.context.ellipse(150, 500, 50, 100, 0, 0, Math.PI, true)
this.context.fill()
})
}
.height('100%')
.width('100%')
}
}
效果如下:
除此之外,CanvasRenderingContext2D 具有更大的自定义空间,例如绘制文本,图片,渐变色和一些不规则图形等。
ts
@Entry
@Component
struct Index {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
build() {
Column() {
Canvas(this.context).width('100%').height('100%').onReady(() => {
this.context.strokeStyle = Color.Blue
this.context.fillStyle = Color.Red
this.context.font = '100px'
/**
* 绘制填充文本或描边文本
* 参数(文本内容,文本起始x坐标,文本起始y坐标)
*/
this.context.strokeText("纯血", 88, 100)
this.context.fillText("鸿蒙", 88, 200)
/**
* 渐变色,createLinearGradient(线性渐变的起点x坐标,线性渐变的起点y坐标,线性渐变的终点x坐标,线性渐变的终点y坐标)
*/
let gradient = this.context.createLinearGradient(88, 300, 288, 300)
gradient.addColorStop(0.0, '#fff32405')
gradient.addColorStop(0.5, '#ff617ef3')
gradient.addColorStop(1.0, '#ffafec06')
this.context.fillStyle = gradient
this.context.fillRect(88, 300, 200, 200)
})
}
.height('100%')
.width('100%')
}
}
效果如下:
绘制图片可以使用离屏绘制,离屏绘制是指将需要绘制的内容先绘制在缓存区,再将其转换成图片,一次性绘制到 Canvas 上。
先准备好本地图片
ts
@Entry
@Component
struct Index {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
private img: ImageBitmap = new ImageBitmap("/images/startIcon.png")
build() {
Column() {
Canvas(this.context).width('100%').height('100%').onReady(() => {
let offContext = this.offCanvas.getContext('2d', this.settings)
// 图片绘制在起点(100,100)为起点,宽高为200的区域
offContext.drawImage(this.img, 100, 100, 200, 200)
//获取(100,100)为起点,宽高100区域的绘制内容
let imageData = offContext.getImageData(100, 100, 100, 100)
//将获取的 imageData 绘制在起点为(100,400)区域中
offContext.putImageData(imageData, 100, 400)
//将离屏绘制的内容画到 Canvas 组件上
let image = this.offCanvas.transferToImageBitmap()
this.context.transferFromImageBitmap(image)
})
}
.height('100%')
.width('100%')
}
}
效果如下:
也可以先定义 Path2D 对象构造路径,然后再进行绘制。
ts
@Entry
@Component
struct Index {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
build() {
Column() {
Canvas(this.context).width('100%').height('100%').onReady(() => {
this.context.strokeStyle = Color.Red
this.context.lineWidth = 3
let path = new Path2D()
path.moveTo(100, 100)
path.lineTo(100, 200)
path.lineTo(200, 300)
path.closePath()
this.context.stroke(path)
})
}
.height('100%')
.width('100%')
}
}
效果如下: