Flutter自定义Paint实现带圆角曲线的左右移动锯齿线动画
带圆角曲线的移动锯齿线动画实现方案
我需要实现一个从左到右移动的带圆角曲线的锯齿线动画,但当前用CustomPainter写的代码生成的是直边锯齿线,怎么修改才能让线条带有圆角曲线?
目标效果:锯齿的转角处为平滑圆角,整体线条流畅
当前效果:锯齿边角尖锐,线条生硬
解决方案
核心思路是把原代码中直接用lineTo连接点的方式,替换为**二次贝塞尔曲线(quadraticBezierTo)**实现圆角过渡,同时统一处理所有线段的平滑连接,而非仅在边界处做处理。以下是修改后的完整代码:
import 'dart:math' as math; import 'package:flutter/material.dart'; class DigitalWavePainter extends CustomPainter { final double animationValue; final double widthOfCanvas; final double heightOfCanvas; DigitalWavePainter(this.animationValue, this.widthOfCanvas, this.heightOfCanvas); @override void paint(Canvas canvas, Size size) { final width = widthOfCanvas; final height = heightOfCanvas; final path = Path(); final path2 = Path(); final numSegments = 200; final segmentWidth = width / numSegments; final amplitude = height + 10; final upperBoundary = height * 0.01; final lowerBoundary = height; final waveProgress = animationValue * 2; double dotY = 0; // 构建右侧路径 path.moveTo(width, (math.sin(0) * amplitude) + height / 2); for (int i = 1; i <= numSegments / 2; i++) { final x = width - i * segmentWidth; final prevX = width - (i - 1) * segmentWidth; final animationTime = (x / width * math.pi) + waveProgress * math.pi; final y = (math.sin(animationTime) * amplitude) + height / 12; final clampedY = y.clamp(upperBoundary, lowerBoundary); dotY = clampedY; // 二次贝塞尔曲线实现圆角过渡 final controlX = (prevX + x) / 2; path.quadraticBezierTo(prevX, clampedY, controlX, clampedY); path.quadraticBezierTo(controlX, clampedY, x, clampedY); } // 构建左侧路径 path2.moveTo(-50, (math.sin(0) * amplitude) + height / 2); for (int i = 1; i <= numSegments; i++) { final x = i * segmentWidth; final prevX = (i - 1) * segmentWidth; final animationTime = (x / width * math.pi) + waveProgress * math.pi; final y = (math.sin(animationTime) * amplitude) + height / 12; final clampedY = y.clamp(upperBoundary, lowerBoundary); dotY = clampedY; // 二次贝塞尔曲线实现圆角过渡 final controlX = (prevX + x) / 2; path2.quadraticBezierTo(prevX, clampedY, controlX, clampedY); path2.quadraticBezierTo(controlX, clampedY, x, clampedY); } const dotRadius = 20.0; final paint = Paint() ..color = Colors.blue ..strokeWidth = 16.0 ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round; final circlePaint = Paint() ..color = Colors.blue ..style = PaintingStyle.fill; final boundaryPaint = Paint() ..color = Colors.white ..style = PaintingStyle.stroke ..strokeWidth = 5.0; canvas.drawPath(path, paint); canvas.drawPath(path2, paint); canvas.drawCircle( Offset(width / 2, dotY + animationValue), dotRadius, circlePaint, ); canvas.drawCircle(Offset(width / 2, dotY), dotRadius, boundaryPaint); } @override bool shouldRepaint(DigitalWavePainter oldDelegate) { return oldDelegate.animationValue != animationValue; } }
关键修改点说明
- 移除原代码中仅在边界处使用贝塞尔曲线的逻辑,改为对所有线段使用二次贝塞尔曲线连接,确保每个锯齿转角都有圆角。
- 使用
clamp()方法统一处理Y值的上下边界,简化重复的条件判断。 - 每个线段的控制点取前后两点的X坐标中点,保证圆角过渡自然流畅。
- 保留原有动画逻辑,确保锯齿线的移动效果不受影响。
内容的提问来源于stack exchange,提问作者Waleed Ahmed
相关产品推荐
相关产品推荐

