ArkUI Canvas:画布一开,页面终于能自己动笔

举报
蓝瘦的蜕变 发表于 2026/09/04 14:32:28 2026/09/04
【摘要】 这一篇我们只做 Canvas 入门。不开动画循环,不做离屏绘制,也不处理图片像素;先把最基础的 2D 绘制跑通。 Canvas 和 Shape 的区别 Shape 更像声明式小图形,适合简单矢量元素。Canvas 更像一张画纸,我们拿到 CanvasRenderingContext2D 后,用命令一笔一笔画。 Demo

ArkUI Canvas:画布一开,页面终于能自己动笔

这一篇我们只做 Canvas 入门。不开动画循环,不做离屏绘制,也不处理图片像素;先把最基础的 2D 绘制跑通。

Canvas 和 Shape 的区别

Shape 更像声明式小图形,适合简单矢量元素。Canvas 更像一张画纸,我们拿到 CanvasRenderingContext2D 后,用命令一笔一笔画。

Demo 里只画了四类东西:

  • fillRectstrokeRect:左上角的矩形。
  • arc:右上角的圆。
  • moveTolineTo:中下方的折线。
  • fillText:左下角的文字。

context 不要写成状态

这里有个很实际的坑:CanvasRenderingContext2DRenderingContextSettings 是绘制上下文,不是页面状态。我们把它们写成普通私有字段就好。

private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);

真正绘制的动作放在 onReady 里:

Canvas(this.context)
  .width(320)
  .height(220)
  .onReady(() => {
    this.drawCanvas();
  })

onReady 表示画布准备好了。这时候再调 fillRectarcfillText,才不会出现上下文还没准备好就开始画的问题。

先画一次就够了

这一篇是第一步,所以我们只画一次。后面如果要做动画、图表、手写板,再考虑定时刷新、手势输入、性能和离屏绘制。入门时先别把这些全塞进来。

你最想用 Canvas 画什么?小图表、签名板、游戏元素,还是某个业务里的自定义装饰?这个答案会决定下一步该补哪一类能力。

参考文档: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-drawing-customization-on-canvas

完整示例代码

文件位置:entry/src/main/ets/pages/arkUI/drawing/ArkUICanvasDemo.ets

@Entry
@Component
struct ArkUICanvasDemo {
  private settings: RenderingContextSettings = new RenderingContextSettings(true);
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);

  private drawCanvas() {
    this.context.clearRect(0, 0, 320, 220);

    this.context.fillStyle = '#F8FAFC';
    this.context.fillRect(0, 0, 320, 220);

    this.context.fillStyle = '#DBEAFE';
    this.context.fillRect(24, 24, 120, 72);
    this.context.strokeStyle = '#2563EB';
    this.context.lineWidth = 4;
    this.context.strokeRect(24, 24, 120, 72);

    this.context.beginPath();
    this.context.arc(232, 62, 36, 0, 2 * Math.PI);
    this.context.fillStyle = '#DCFCE7';
    this.context.fill();
    this.context.strokeStyle = '#0F766E';
    this.context.lineWidth = 4;
    this.context.stroke();

    this.context.beginPath();
    this.context.moveTo(36, 166);
    this.context.lineTo(112, 126);
    this.context.lineTo(198, 168);
    this.context.lineTo(284, 120);
    this.context.strokeStyle = '#C2410C';
    this.context.lineWidth = 5;
    this.context.stroke();

    this.context.fillStyle = '#111827';
    this.context.font = 'bold 18px sans-serif';
    this.context.fillText('Canvas', 24, 206);
  }

  @Builder
  sectionTitle(title: string, desc: string) {
    Column({ space: 4 }) {
      Text(title)
        .width('100%')
        .fontSize(16)
        .fontWeight(700)
        .fontColor('#0F172A')

      Text(desc)
        .width('100%')
        .fontSize(13)
        .fontColor('#64748B')
        .lineHeight(20)
    }
    .width('100%')
    .alignItems(HorizontalAlign.Start)
  }

  build() {
    Scroll() {
      Column({ space: 18 }) {
        Text('ArkUI Canvas')
          .width('100%')
          .fontSize(24)
          .fontWeight(700)
          .fontColor('#0F172A')

        Text('画布一开,页面终于能自己动笔')
          .width('100%')
          .fontSize(22)
          .fontWeight(700)
          .fontColor('#111827')

        Text('Canvas 更像一张真正的画纸。我们拿到 2D 上下文后,在 onReady 里画矩形、圆弧、折线和文字。')
          .width('100%')
          .fontSize(14)
          .fontColor('#64748B')
          .lineHeight(22)

        Column({ space: 12 }) {
          this.sectionTitle('先准备 CanvasRenderingContext2D', 'RenderingContextSettings 用来创建 2D 绘制上下文。注意这里不要把 context 写成 @State,它不是页面状态。')

          Canvas(this.context)
            .width(320)
            .height(220)
            .backgroundColor('#FFFFFF')
            .border({ width: 1, color: '#CBD5E1' })
            .borderRadius(8)
            .onReady(() => {
              this.drawCanvas();
            })
        }
        .width('100%')
        .padding(16)
        .backgroundColor('#EFF6FF')
        .borderRadius(8)

        Column({ space: 12 }) {
          this.sectionTitle('这一张画布里画了什么', 'fillRect 画填充矩形,strokeRect 画边框矩形,arc 画圆弧,moveTo 和 lineTo 连出折线,fillText 写文字。')

          Column({ space: 10 }) {
            Text('fillRect + strokeRect:左上角的蓝色矩形')
              .fontSize(13)
              .fontColor('#475569')
            Text('beginPath + arc:右上角的绿色圆')
              .fontSize(13)
              .fontColor('#475569')
            Text('moveTo + lineTo:中下方的橙色折线')
              .fontSize(13)
              .fontColor('#475569')
            Text('fillText:左下角的 Canvas 文字')
              .fontSize(13)
              .fontColor('#475569')
          }
          .width('100%')
          .padding(14)
          .backgroundColor('#FFFFFF')
          .borderRadius(8)
          .alignItems(HorizontalAlign.Start)
        }
        .width('100%')
        .padding(16)
        .backgroundColor('#F8FAFC')
        .borderRadius(8)
      }
      .width('100%')
      .padding(20)
      .alignItems(HorizontalAlign.Start)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。