HarmonyOS鸿蒙Next中如何在应用中实现 Canvas 水波进度动画效果?
HarmonyOS鸿蒙Next中如何在应用中实现 Canvas 水波进度动画效果? 如何在鸿蒙应用中实现 Canvas 水波进度动画效果?
简单来讲要实现鸿蒙应用中的 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;
}
}
四、效果展示

更多关于HarmonyOS鸿蒙Next中如何在应用中实现 Canvas 水波进度动画效果?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,可以通过Canvas组件结合动画API实现水波进度动画。以下是核心实现步骤:
-
创建Canvas组件:在ArkUI中使用Canvas组件作为绘制区域。
Canvas(this.context) .width('100%') .height('100%') -
定义水波绘制函数:使用贝塞尔曲线模拟水波效果,通过正弦函数控制波形。
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); } // 应用填充和绘制 } -
实现动画循环:使用requestAnimationFrame或ArkUI动画系统更新偏移量。
private animate() { this.offset += 0.1; // 控制波速 this.drawWave(this.progress); requestAnimationFrame(this.animate.bind(this)); } -
关联进度值:将水波位置与进度值绑定,通过clip区域控制显示范围。
// 根据进度值裁剪画布显示区域 const clipPath = new Path2D(); clipPath.rect(0, this.height * (1 - progress), this.width, this.height); -
性能优化:使用离屏Canvas预渲染静态部分,避免重复计算。
关键点:通过正弦函数生成波形,动态调整相位偏移实现动画效果,结合Canvas裁剪实现进度控制。注意在aboutToDisappear生命周期中停止动画循环。


