如何实现拐角随走向弯曲的音频波形(基于UIBezierPath)
嘿,我来帮你搞定这个音频波形拐角弯曲的问题!你的现有代码用addLine(to:)绘制直线段来构建波形,所以所有拐角都是尖锐的直角。根据你的需求,我整理了两种常见的实现方案,你可以根据想要的视觉效果来选:
方案一:给单个波形竖线添加圆角拐角
如果你的波形是由多个垂直短线组成(就像当前代码的逻辑),我们可以把每个短线改成带圆角的小矩形,让顶部和底部的拐角变得圆润。修改后的代码如下:
fileprivate func createPath(with points: [CGPoint], pointCount: Int, in rect: CGRect) -> CGPath { let path = UIBezierPath() guard pointCount > 0, rect.height > 0, rect.width > 0 else { return path.cgPath } let minValue = 1 / (rect.height / 2) let cornerRadius: CGFloat = 3 // 可以根据视觉需求调整圆角大小 let scaleX = (rect.width - 1) / CGFloat(pointCount - 1) let halfHeight = rect.height / 2 let scaleY = halfHeight var transform = CGAffineTransform(scaleX: scaleX, y: scaleY) transform.ty = halfHeight for index in 0..<(pointCount / 2) { var startPoint = points[index * 2] var endPoint = startPoint endPoint.y = max(endPoint.y, minValue) endPoint.y = -endPoint.y // 计算竖线的宽度,反向抵消缩放影响,保证最终显示宽度合适 let lineWidth = 1 / scaleX // 用带圆角的矩形替代原来的直线 let lineRect = CGRect( x: startPoint.x - lineWidth/2, y: min(startPoint.y, endPoint.y), width: lineWidth, height: abs(endPoint.y - startPoint.y) ) let roundedLinePath = UIBezierPath(roundedRect: lineRect, cornerRadius: cornerRadius) path.append(roundedLinePath) } path.apply(transform) return path.cgPath }
小说明:
- 把单条直线换成带圆角的矩形后,每个波形竖线的顶底拐角就会呈现自然的弯曲效果
cornerRadius参数可以自由调整,数值越大拐角越圆润- 计算
lineWidth是为了抵消后续的缩放变换,确保竖线宽度在不同容器尺寸下都保持一致
方案二:绘制连续平滑的波形曲线
如果想要更流畅的连续波形(类似音乐APP里常见的那种平滑音频曲线),可以用贝塞尔曲线替代直线连接离散点,让整个线条的拐角自然弯曲。修改后的代码如下:
fileprivate func createPath(with points: [CGPoint], pointCount: Int, in rect: CGRect) -> CGPath { let path = UIBezierPath() guard pointCount > 1, rect.height > 0, rect.width > 0 else { return path.cgPath } let minValue = 1 / (rect.height / 2) let scaleX = (rect.width - 1) / CGFloat(pointCount - 1) let halfHeight = rect.height / 2 let scaleY = halfHeight var transform = CGAffineTransform(scaleX: scaleX, y: scaleY) transform.ty = halfHeight // 先预处理所有点,调整y值并确保最小值 let processedPoints = points.enumerated().map { index, point in var adjustedPoint = point if index % 2 == 0 { adjustedPoint.y = max(adjustedPoint.y, minValue) adjustedPoint.y = -adjustedPoint.y } return adjustedPoint } // 从第一个点开始绘制 path.move(to: processedPoints[0]) // 用二次贝塞尔曲线连接每个点,实现平滑弯曲 for index in 1..<processedPoints.count { let currentPoint = processedPoints[index] let prevPoint = processedPoints[index-1] // 取两点中点作为控制点,让曲线自然过渡 let controlPoint = CGPoint( x: (prevPoint.x + currentPoint.x)/2, y: (prevPoint.y + currentPoint.y)/2 ) path.addQuadCurve(to: currentPoint, controlPoint: controlPoint) } path.apply(transform) return path.cgPath }
小说明:
- 二次贝塞尔曲线通过控制点来实现线条的平滑弯曲,完全消除了直线的尖锐拐角
- 如果需要更精细的曲线调整,可以改用三次贝塞尔曲线
addCurve(to:controlPoint1:controlPoint2:),通过两个控制点来精准控制弯曲走向
额外小提示
- 如果需要上下对称的完整波形,可以在绘制完上半部分后,镜像绘制下半部分的曲线
- 调整缩放参数时,可以配合圆角大小或控制点计算,确保在不同尺寸的容器里都能保持理想的视觉效果
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

