HarmonyOS鸿蒙Next中Canvas drawImage只响应一次

HarmonyOS鸿蒙Next中Canvas drawImage只响应一次

@ComponentV2
export struct ArcImageCrop {
    @Local private angle: number = Math.PI
    // canvas参数
    private settings: RenderingContextSettings = new RenderingContextSettings(true);
    private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
    private img: image.PixelMap | null = null;

    aboutToAppear(): void {
        const fileUri = ProjectUtils.getCurrProjectImageUri('60')!
        this.img = ImageUtils.sandBoxImageToImagePixelMap(fileUri.toString())
    }

    @Monitor('angle')
    onAngleChange() {
        if (this.context) {
            LogUtils.debug("this.angle === " + this.angle)
            let width = AppUtil.getUIContext().px2vp(500);
            // 清空画布
            this.context.clearRect(0, 0, width, width);
            // 创建扇形路径
            this.context.beginPath();
            this.context.moveTo(width / 2, width / 2);
            this.context.arc(width / 2, width / 2, width / 2, Math.PI, this.angle);
            this.context.closePath();
            this.context.stroke();
            // 应用裁剪
            this.context.clip();
            // 绘制图片
            this.context.drawImage(this.img, 0, 0, width, width);

        }
    }
    build() {
        RelativeContainer() {
            Canvas(this.context)
                .width(AppUtil.getUIContext().px2vp(500))
                .height(AppUtil.getUIContext().px2vp(500))
                .backgroundColor('#f0f0f0')
                .onReady(() => {
                    this.context.strokeStyle = "rgba(255,0,0,1)";
                    this.context.fillStyle = "rgba(255,0,0,1)";
                    this.context.lineWidth = 1;
                })
            Button('点我')
                .position({ y: -50 })
                .onClick(() => {
                    this.angle += Math.PI / 4
                })
        }
        .width('100%')
        .height('100%')

    }
}
这个代码为什么Canvas只绘制一次图片, LogUtils.debug("this.angle === " + this.angle)是有输出的

更多关于HarmonyOS鸿蒙Next中Canvas drawImage只响应一次的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

开发者您好,clearRect方法仅能清除绘制内容,但是之前clip裁剪的路径无法清除,所以需要在每次调用onAngleChange时,需要先添加reset操作来清空画布,示例代码如下:

@Monitor('angle')
onAngleChange() {
  if (this.context) {
    console.info('this.angle === ' + this.angle);
    let width = this.getUIContext().px2vp(500); // 重置
    this.context.reset(); // 清空画布      
    this.context.clearRect(0, 0, width, width); // 创建扇形路径
    this.context.beginPath();
    this.context.moveTo(width / 2, width / 2);
    this.context.arc(width / 2, width / 2, width / 2, Math.PI, this.angle);
    this.context.closePath();
    this.context.stroke(); // 应用裁剪      
    this.context.clip(); // 绘制图片      
    this.context.drawImage(this.img, 0, 0, width, width);
  }
}

更多关于HarmonyOS鸿蒙Next中Canvas drawImage只响应一次的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,Canvas的drawImage方法只响应一次通常是由于Canvas渲染机制或状态未重置导致的。确保每次调用drawImage前,Canvas上下文已正确更新,并检查图像资源是否加载完成。避免在单次绘制周期内重复调用,或尝试使用requestAnimationFrame进行连续绘制。

问题出在Canvas的绘制状态管理上。在HarmonyOS Next的Canvas中,clip()方法会永久改变裁剪区域,导致后续绘制被限制。

你的代码中,每次onAngleChange()调用都会执行:

  1. clearRect() 清空画布
  2. 创建新的扇形路径
  3. clip() 应用新的裁剪区域
  4. drawImage() 绘制图片

clip()是累积的,第二次调用时会在第一次的裁剪区域基础上再次裁剪,可能导致有效绘制区域为零。

解决方案: 使用save()restore()来管理状态:

onAngleChange() {
    if (this.context) {
        LogUtils.debug("this.angle === " + this.angle)
        let width = AppUtil.getUIContext().px2vp(500);
        
        // 清空画布
        this.context.clearRect(0, 0, width, width);
        
        // 保存当前状态
        this.context.save();
        
        // 创建扇形路径
        this.context.beginPath();
        this.context.moveTo(width / 2, width / 2);
        this.context.arc(width / 2, width / 2, width / 2, Math.PI, this.angle);
        this.context.closePath();
        this.context.stroke();
        
        // 应用裁剪
        this.context.clip();
        
        // 绘制图片
        this.context.drawImage(this.img, 0, 0, width, width);
        
        // 恢复之前的状态,清除裁剪区域
        this.context.restore();
    }
}

save()会保存当前绘图状态(包括裁剪区域、变换矩阵等),restore()会恢复到这个状态,这样每次都是全新的绘制环境。

另外,确保this.img已正确加载且不为null,可以在drawImage前添加空值检查。

回到顶部