HarmonyOS鸿蒙Next中如何在应用中实现 Canvas 水波进度动画效果?

HarmonyOS鸿蒙Next中如何在应用中实现 Canvas 水波进度动画效果? 如何在鸿蒙应用中实现 Canvas 水波进度动画效果?

3 回复

简单来讲要实现鸿蒙应用中的 Canvas 水波进度动画,核心是利用 Canvas 的 Path 绘制正弦波形模拟水波,结合状态管理实现动画循环,搭配滑块完成进度交互,以下是详细实现思路和原理解析:

一、核心原理解析

水波路径生成原理:水波本质是正弦曲线(y = A*sin(ωx+φ)+k),通过计算不同 x 坐标对应的 y 值生成连续波形。其中:

A(振幅)控制水波高度,ω(角频率)控制水波密度,φ(相位偏移)实现水波流动动画;

结合进度值计算水位高度(waterLevel),进度越高水位越低;

闭合路径时连接圆形底部,使水波被限制在圆形区域内。

动画循环原理:通过setInterval不断更新相位偏移值(waveOffset),触发组件重新渲染,因正弦曲线相位变化,视觉上呈现水波流动效果。

圆形裁剪原理:给 Canvas 组件设置clip(new Circle(…)),裁剪掉圆形外的内容,让水波仅显示在圆形区域内,模拟 “水球” 效果。

二、关键代码实现

状态管理:用@State装饰waveOffset(相位偏移)和progress(进度值),状态变化自动触发 UI 刷新。

水波路径绘制:

// 生成水波路径
private getWavePath(): string {
  const centerX = 100;
  const centerY = 100;
  const radius = 90;
  const waveHeight = 10;
  const waterLevel = centerY + (100 - this.progress) * radius / 100;

  let path = `M${centerX - radius},${waterLevel}`;

  // 绘制正弦波形
  for (let x = -radius; x <= radius; x += 2) {
    const y = waterLevel + Math.sin(x / radius * Math.PI + this.waveOffset) * waveHeight;
    path += ` L${centerX + x},${y}`;
  }

  // 闭合路径
  path += ` L${centerX + radius},${centerY + radius} L${centerX - radius},${centerY + radius} Z`;
  return path;
}

动画与交互:

页面加载时(onAppear)启动定时器,更新waveOffset实现水波流动;

滑块(Slider)绑定progress状态,滑动时实时修改进度值,联动水位高度变化。

UI 结构:用Stack堆叠圆形边框和 Canvas,Canvas 内叠加进度文字,通过clip裁剪实现圆形水波效果。

三、完整代码

@Entry
@Component
struct WaterWaveDemo {
  [@State](/user/State) waveOffset: number = 0;
  [@State](/user/State) progress: number = 68; // 进度百分比

  build() {
    Column() {
      Text('Canvas水波进度动画')
        .fontSize(26)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 40, bottom: 30 });

      // 水波动画Canvas
      Stack() {
        // 外层圆形容器
        Circle()
          .stroke(Color.Grey)
          .strokeWidth(2)
          .opacity(0.3)
          .width(200)
          .height(200);

        // 水波Canvas
        Canvas() {
          // 绘制水波路径
          Path()
            .commands(this.getWavePath())
            .fill('#3498DB')
            .opacity(0.6);

          // 绘制进度文字
          Text(`${this.progress}%`)
            .fontSize(36)
            .fontWeight(FontWeight.Bold)
            .fontColor('#2980B9');
        }
        .width(200)
        .height(200)
        .clip(new Circle({ width: 200, height: 200 }));
      }
      .margin({ bottom: 40 });

      // 进度控制滑块
      Slider({
        value: this.progress,
        min: 0,
        max: 100,
        style: SliderStyle.OutSet
      })
        .width('80%')
        .blockColor('#3498DB')
        .selectedColor('#3498DB')
        .onChange((value) => {
          this.progress = value;
        });
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
    .justifyContent(FlexAlign.Center)
    .onAppear(() => {
      // 水波动画循环
      setInterval(() => {
        this.waveOffset += 0.1;
        if (this.waveOffset > Math.PI * 2) {
          this.waveOffset = 0;
        }
      }, 50);
    });
  }

  // 生成水波路径
  private getWavePath(): string {
    const centerX = 100;
    const centerY = 100;
    const radius = 90;
    const waveHeight = 10;
    const waterLevel = centerY + (100 - this.progress) * radius / 100;

    let path = `M${centerX - radius},${waterLevel}`;

    // 绘制正弦波形
    for (let x = -radius; x <= radius; x += 2) {
      const y = waterLevel + Math.sin(x / radius * Math.PI + this.waveOffset) * waveHeight;
      path += ` L${centerX + x},${y}`;
    }

    // 闭合路径
    path += ` L${centerX + radius},${centerY + radius} L${centerX - radius},${centerY + radius} Z`;
    return path;
  }
}

四、效果展示

cke_18842.png

更多关于HarmonyOS鸿蒙Next中如何在应用中实现 Canvas 水波进度动画效果?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中实现Canvas水波进度动画

在HarmonyOS Next中实现Canvas水波进度动画,可使用ArkTS的Canvas组件。通过CanvasRenderingContext2D绘制正弦波形,结合动画函数动态更新相位偏移实现波动效果。

关键步骤:

  1. 创建Canvas组件并获取绘图上下文;
  2. 使用贝塞尔曲线或正弦函数绘制水波路径;
  3. 通过定时器或动画帧回调更新相位值;
  4. 配合clip裁剪实现进度控制。

需注意使用HarmonyOS的图形绘制API,避免使用Web Canvas API。

在HarmonyOS Next中,可以通过Canvas组件结合动画API实现水波进度动画。以下是核心实现步骤:

  1. 创建Canvas组件:在ArkUI中使用Canvas组件作为绘制区域。

    Canvas(this.context)
      .width('100%')
      .height('100%')
    
  2. 定义水波绘制函数:使用贝塞尔曲线模拟水波效果,通过正弦函数控制波形。

    private drawWave(progress: number) {
      const path = new Path2D();
      const waveWidth = 0.05; // 波长控制
      const waveHeight = 10; // 波高控制
      
      for (let x = 0; x <= this.width; x++) {
        const y = waveHeight * Math.sin(x * waveWidth + this.offset);
        path.lineTo(x, y);
      }
      // 应用填充和绘制
    }
    
  3. 实现动画循环:使用requestAnimationFrame或ArkUI动画系统更新偏移量。

    private animate() {
      this.offset += 0.1; // 控制波速
      this.drawWave(this.progress);
      requestAnimationFrame(this.animate.bind(this));
    }
    
  4. 关联进度值:将水波位置与进度值绑定,通过clip区域控制显示范围。

    // 根据进度值裁剪画布显示区域
    const clipPath = new Path2D();
    clipPath.rect(0, this.height * (1 - progress), this.width, this.height);
    
  5. 性能优化:使用离屏Canvas预渲染静态部分,避免重复计算。

关键点:通过正弦函数生成波形,动态调整相位偏移实现动画效果,结合Canvas裁剪实现进度控制。注意在aboutToDisappear生命周期中停止动画循环。

回到顶部