You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现Quick Path效果时CAShapeLayer与UIBezierPath绘制出现尖角异常如何解决

问题原因及修复方案

核心问题1:addArc参数单位错误

你定义的degrees计算属性作用是将弧度值转换为角度值,但UIBezierPath的addArc方法要求传入的startAngle、endAngle都是弧度值,你当前传入的是角度值,参数完全不符合要求:

// 错误写法:360.degrees等价于将360弧度转换为角度≈20626度,当作弧度传入会导致圆弧绘制完全异常
path.addArc(withCenter: point,
            radius: width,
            startAngle: CGFloat(0).degrees,
            endAngle: CGFloat(360).degrees,
            clockwise: false)

修改为直接传入弧度值即可:

path.addArc(withCenter: point,
            radius: width,
            startAngle: 0,
            endAngle: .pi * 2,
            clockwise: false)

核心问题2:偏移方向逻辑错误

你需要的是垂直于两点连线方向的左右偏移点,当前代码里newRight用angle-180的写法,实际是沿着连线的反方向偏移,完全不符合路径边缘的构造逻辑,会直接导致相邻段边缘错位出现尖角:

// 错误写法:左右偏移方向完全错误
let newLeft = point.offset(byDistance: width, inDirection: angle)
let newRight = point.offset(byDistance: width, inDirection: angle - 180)

修改为垂直于连线的左右方向即可:

let newLeft = point.offset(byDistance: width, inDirection: angle + 90)
let newRight = point.offset(byDistance: width, inDirection: angle - 90)

核心问题3:路径构造逻辑错误

你现在每遍历一个点就生成一个独立的闭合四边形,重复调用close(),相邻段没有平滑衔接,填充时会出现重叠、镂空的异常,同时在路径生成方法里直接调用fill()、stroke()也不符合绘制逻辑,这两个方法应该放在draw(_ rect:)生命周期里执行。

完整修复后代码示例

func path() -> UIBezierPath {
    let widthMultiplier = maxWidth / CGFloat(points.count)
    let path = UIBezierPath()
    
    guard points.count >= 2 else { return path }
    
    var lastPoint = points[0]
    let initialAngle = lastPoint.angle(to: points[1])
    let initialWidth = widthMultiplier * 1
    var lastLeft = lastPoint.offset(byDistance: initialWidth/2, inDirection: initialAngle + 90)
    var lastRight = lastPoint.offset(byDistance: initialWidth/2, inDirection: initialAngle - 90)
    
    path.move(to: lastLeft)
    
    for (index, point) in points.enumerated() where index > 0 {
        let angle = lastPoint.angle(to: point)
        let currentWidth = widthMultiplier * CGFloat(index)
        let newLeft = point.offset(byDistance: currentWidth/2, inDirection: angle + 90)
        let newRight = point.offset(byDistance: currentWidth/2, inDirection: angle - 90)
        
        path.addLine(to: newLeft)
        if index == points.count - 1 {
            path.addArc(withCenter: point,
                        radius: currentWidth/2,
                        startAngle: (angle + 90) * .pi / 180,
                        endAngle: (angle - 90) * .pi / 180,
                        clockwise: true)
        }
        path.addLine(to: newRight)
        path.addLine(to: lastRight)
        
        lastLeft = newLeft
        lastRight = newRight
        lastPoint = point
    }
    
    path.close()
    path.lineJoinStyle = .round
    path.lineCapStyle = .round
    
    return path
}

内容的提问来源于stack exchange,提问作者Anthony Bell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 10:18:03