HarmonyOS 鸿蒙Next 如何实现动态绘制镂空区域的效果?

发布于 1周前 作者 wuwangju 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 如何实现动态绘制镂空区域的效果?

假设我有两张尺寸相同的图片:图片1和图片2,图片1在图片2下面被图片2挡住,请问如何实现手指滑动的路径区域漏出下方图片1(类似刮奖的效果)?使用 NodeContainer + RenderNode + Pen 是否有办法实现(因为考虑到方便做撤销操作)?谢谢!

2 回复

可以参考如下demo:

@Entry @Component struct Page24040110729022 { @State message: string = ‘Hello World’; private settings: RenderingContextSettings = new RenderingContextSettings(true) private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) @State circleCenterX: number = 0 @State circleCenterY: number = 0 @State circleRadius: number = 100

build() { Row() { Column() { Stack() { Image($r(“app.media.startIcon”)).height(300) Canvas(this.context) .width(‘100%’) .height(‘100%’) .backgroundColor(’#00000000’) .onReady(() => { this.circleCenterX = this.context.width / 2 this.circleCenterY = this.context.height / 2 this.context.fillStyle = “#aa000000” this.context.beginPath() this.context.moveTo(0, 0) this.context.lineTo(0, this.context.height) this.context.lineTo(this.context.width, this.context.height) this.context.lineTo(this.context.width, 0) this.context.lineTo(0, 0) this.context.arc(this.circleCenterX, this.circleCenterY, this.circleRadius, 0, Math.PI * 2) this.context.fill() this.context.closePath() } ).width(‘1456px’) .height(‘1456px’) } .width(‘100%’) } .height(‘100%’) } } }


或者参考以下demo:


import image from '@ohos.multimedia.image'

[@Entry](/user/Entry)
[@Component](/user/Component)
export struct Page240408135324019 {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  [@State](/user/State) x: number = 0
  [@State](/user/State) y: number = 0
  [@State](/user/State) x_left: number = 0
  [@State](/user/State) y_top: number = 0
  [@State](/user/State) iconVisible: boolean = false
  isDrawing: boolean = false
  lastX: number = 0
  lastY: number = 0

  draw(ctx: CanvasRenderingContext2D, fromX: number, fromY: number, toX: number, toY: number) {
    // 使用贝塞尔曲线来绘制平滑路径
    ctx.beginPath()
    ctx.moveTo(fromX, fromY)
    ctx.lineTo(toX, toY)
    ctx.strokeStyle = '#000'
    ctx.lineWidth = 40
    ctx.lineCap = 'round'
    ctx.lineJoin = 'round'
    ctx.stroke()
    ctx.closePath()
  }

  scratch(event: TouchEvent) {
    if (!this.isDrawing) {
      return
    }
    const touch = event.touches[0]
    const x = touch.x
    const y = touch.y
    this.draw(this.context, this.lastX, this.lastY, x, y)
    this.lastX = x
    this.lastY = y
  }

  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      Image($r("app.media.bg")).width(px2vp(698))
      Canvas(this.context)
        .width('100%')
        .height('100%')
        .backgroundColor(Color.Transparent)
        .onReady(() => {
          this.getPixmapFromMedia($r('app.media.img'))
            .then(image => {
              this.context.drawImage(image, this.x, this.y)
              // 设置刮开涂层效果,注意需要先绘制背景在设置
              this.context.globalCompositeOperation = 'destination-out'
            })
        })
        .onTouch((event) => {
          switch (event.type) {
            case 0:
              this.isDrawing = true
              const touch = event.touches[0]
              this.lastX = touch.x
              this.lastY = touch.y
              this.scratch(event)
              break
            case 1:
              this.isDrawing = false
              break
            case 2:
              this.scratch(event)
              break
          }
        }
    }
  }
}

更多关于HarmonyOS 鸿蒙Next 如何实现动态绘制镂空区域的效果?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,实现动态绘制镂空区域的效果,通常可以通过Canvas和相关绘图API来完成。以下是一个基本的实现思路:

首先,你需要创建一个自定义的Component或Shape,并在其onDraw方法中进行绘制。利用Canvas的clipPath方法,可以定义一个镂空区域的路径。然后,在该路径之外进行绘制,以实现镂空效果。

具体步骤如下:

  1. 定义一个Path对象,描述你想要的镂空区域形状。
  2. 在onDraw方法中,先调用Canvas的save方法保存当前画布状态。
  3. 使用Canvas的clipPath方法,传入之前定义的Path对象,设置镂空区域。
  4. 在镂空区域之外进行绘制操作,比如填充背景色或绘制其他图形。
  5. 最后,调用Canvas的restore方法恢复画布到保存时的状态。

注意,为了实现动态效果,你可能需要在某个事件触发时(如按钮点击、滑动等)重新计算Path并调用invalidate方法请求重绘。

示例代码(伪代码,具体实现需根据实际需求调整):

// 省略import语句和类定义
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Path path = new Path();
    // 定义镂空区域形状
    path.addCircle(...);
    
    canvas.save();
    canvas.clipPath(path, Region.Op.DIFFERENCE);
    // 在镂空区域之外绘制
    canvas.drawColor(...);
    // 其他绘制操作
    canvas.restore();
}

// 动态更新路径并请求重绘的方法
public void updatePath() {
    // 重新计算path
    invalidate();
}

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部