找了很久水波纹动画(不是扩散的那种水波纹),没找到,都是看来没人搞,那我来搞一个吧,线上图看效果,注释写的很详细了,我就不过多阐述了,看代码吧
@Entry @Component struct WaterWaveBall { private settings: RenderingContextSettings = new RenderingContextSettings(true); private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); @State private phase: number = 0; // 波浪相位 private timer: number = 0; // 定时器ID private centerX: number = 100; // 球心X坐标(200/2=100) private centerY: number = 100; // 球心Y坐标(200/2=100) private radius: number = 100; // 球体半径(留出边框空间) private amplitude: number = 10; // 波浪振幅(按比例缩小) private waveLength: number = 180; // 波浪长度(按比例缩小) private waterLevel: number = 180; // 水位高度(按比例缩小) private waveSpeed: number = 2; // 波浪速度(按比例调整) aboutToAppear() { // 启动波浪动画 this.setprogress(0.5) this.startWaveAnimation(); } aboutToDisappear() { // 清除定时器 if (this.timer) { clearInterval(this.timer); this.timer = 0; } } setprogress(p: number) { this.waterLevel = 180 - 180 * p } // 启动波浪动画 startWaveAnimation() { if (!this.timer) { this.timer = setInterval(() => { // 更新波浪相位 - 确保波浪由左向右移动 this.phase = (this.phase + this.waveSpeed) % this.waveLength; }, 30); } } // 计算波浪Y坐标(确保波浪向右移动) calculateWaveY(x: number, phase: number): number { return this.waterLevel + this.amplitude * Math.sin(2 * Math.PI * (x - phase) / this.waveLength); } // 绘制波浪(尺寸优化版) drawWave(ctx: CanvasRenderingContext2D) { const canvasSize = 200; // 画布尺寸改为200 // 1. 清除画布 ctx.clearRect(0, 0, canvasSize, canvasSize); // 2. 绘制绿色边框 ctx.beginPath(); ctx.arc(this.centerX, this.centerY, this.radius, 0, Math.PI * 2); ctx.lineWidth = 20; ctx.strokeStyle = Color.Orange; ctx.stroke(); // 3. 设置圆形裁剪区域 ctx.beginPath(); ctx.arc(this.centerX, this.centerY, this.radius - 10, 0, Math.PI * 2); ctx.clip(); // 4. 绘制水面区域(粉色)- 波浪由左向右移动 ctx.beginPath(); // 起始点 const startY = this.calculateWaveY(0, this.phase); ctx.moveTo(0, startY); // 使用二次贝塞尔曲线绘制主波浪 const points = 30; // 减少点数以适应小尺寸 for (let i = 1; i <= points; i++) { const x = (i / points) * canvasSize; const y = this.calculateWaveY(x, this.phase); // 前一个点 const prevX = ((i - 1) / points) * canvasSize; const prevY = this.calculateWaveY(prevX, this.phase); // 计算控制点(取中点) const cpx = (prevX + x) / 2; const cpy = (prevY + y) / 2; // 使用二次贝塞尔曲线 ctx.quadraticCurveTo(cpx, cpy, x, y); } // 封闭路径 ctx.lineTo(canvasSize, canvasSize); ctx.lineTo(0, canvasSize); ctx.closePath(); // 5. 填充波浪区域(粉色渐变) const gradient = ctx.createLinearGradient(0, this.waterLevel - 25, 0, canvasSize); gradient.addColorStop(0, '#3de1ad'); // 浅绿色 gradient.addColorStop(0.7, '#0eb83a'); // 绿色 gradient.addColorStop(1, '#0c8918'); // 深绿色 ctx.fillStyle = gradient; ctx.fill(); // 6. 绘制球体内部的渐变效果 ctx.beginPath(); ctx.arc(this.centerX, this.centerY, this.radius - 2, 0, Math.PI * 2); const ballGradient = ctx.createRadialGradient( this.centerX, this.centerY - 15, 10, this.centerX, this.centerY, this.radius ); ballGradient.addColorStop(0, 'rgba(224, 247, 250, 0.9)'); ballGradient.addColorStop(0.7, 'rgba(224, 247, 250, 0.5)'); ballGradient.addColorStop(1, 'rgba(224, 247, 250, 0.1)'); ctx.fillStyle = ballGradient; ctx.fill(); } build() { Column() { // 标题 Text('小型球体水波浪动画') .fontSize(20) .fontWeight(FontWeight.Bold) .margin({ bottom: 15 }) .fontColor('#333') // 球形容器 Stack() { // 绘制波浪球 Canvas(this.context) .width(200) .height(200) .onReady(() => { // 初始绘制 this.drawWave(this.context); // 设置动画循环 setInterval(() => { this.drawWave(this.context); }, 30); }) } .width(200) .height(200) .borderRadius(100) .margin({ bottom: 15 }) .backgroundColor('#387ec3') .clip(true) // 确保内容被裁剪为圆形 } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Center) .backgroundColor('#F5F5F5') .padding(20) } }