纯血鸿蒙 - 图形绘制详解

常规几何图形

鸿蒙有专门的绘制组件,如 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%')
  }
}

效果如下:

相关推荐
诗歌难吟46415 分钟前
初识ArkUI
harmonyos
SameX29 分钟前
HarmonyOS Next 设备安全特性深度剖析学习
harmonyos
郭梧悠2 小时前
HarmonyOS(57) UI性能优化
ui·性能优化·harmonyos
郝晨妤12 小时前
鸿蒙原生应用开发元服务 元服务是什么?和App的关系?(保姆级步骤)
android·ios·华为od·华为·华为云·harmonyos·鸿蒙
Peace*12 小时前
HarmonyOs鸿蒙开发实战(16)=>沉浸式效果第一种方案一窗口全屏布局方案
harmonyos·鸿蒙·鸿蒙系统
howard200515 小时前
鸿蒙实战:页面跳转传参
harmonyos·跳转·router·传参
威哥爱编程1 天前
异步编程在ArkTS中具体怎么实现?
harmonyos·arkts·harmonyos next
ChinaDragonDreamer1 天前
HarmonyOS:UIAbility组件间交互(设备内)
开发语言·harmonyos·鸿蒙
jikuaidi6yuan1 天前
鸿蒙系统简介
华为·harmonyos
何遇mirror1 天前
【话题】抓住鸿蒙生态崛起的机遇:挑战与对策
华为·harmonyos