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

iOS开发:如何确定连接UIView圆形的二次贝塞尔曲线控制点?

解决二次贝塞尔曲线连接圆形的控制点问题

嘿,我完全懂你现在的困扰——二次贝塞尔曲线的控制点确实是让曲线和圆形自然衔接的核心!你当前代码里的控制点(point1.x+point2.x, point1.y)会把曲线往x轴方向拉得特别远,肯定不是你想要的效果。下面我给你两种实用的解决方案,根据你想要的曲线风格来选:

方案1:外凸/内凹的平滑曲线(适合气泡、节点连接效果)

这种思路是基于两个点(或者圆心)的中点,加上垂直于两点连线的偏移量来计算控制点,这样曲线会呈现自然的弯曲效果。

修改后的函数代码:

func drawLineFromPoint(point1: CGPoint, point2: CGPoint, curveOffset: CGFloat = 50) {
    let path = UIBezierPath()
    path.move(to: point1)
    
    // 计算两点连线的向量
    let dx = point2.x - point1.x
    let dy = point2.y - point1.y
    // 取两点的中点
    let midPoint = CGPoint(x: (point1.x + point2.x)/2, y: (point1.y + point2.y)/2)
    // 计算垂直于连线的单位向量(控制弯曲方向)
    let lineLength = sqrt(dx*dx + dy*dy)
    let perpendicularX = -dy / lineLength
    let perpendicularY = dx / lineLength
    // 生成控制点:中点加上垂直方向的偏移量
    let controlPoint = CGPoint(x: midPoint.x + perpendicularX * curveOffset, y: midPoint.y + perpendicularY * curveOffset)
    
    path.addQuadCurve(to: point2, controlPoint: controlPoint)
    path.flatness = 0.9
    
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    shapeLayer.strokeColor = UIColor.blue.cgColor
    shapeLayer.lineWidth = 5
    shapeLayer.fillColor = UIColor.clear.cgColor
    self.centerView.layer.addSublayer(shapeLayer)
}

关键说明:

  • curveOffset参数:值越大,曲线弯曲程度越高;用负数的话,曲线会向相反方向弯曲(从外凸变内凹)。
  • 垂直向量的方向:如果想要曲线往另一侧弯,把perpendicularX和perpendicularY的符号反过来就行(比如改成perpendicularX = dy / lineLength,perpendicularY = -dx / lineLength)。

方案2:贴合圆形边缘的曲线(更精准的连接)

如果你的圆形是有固定半径的,最好让曲线从圆的边缘出发,而不是圆心。这个方案会先计算圆上的切点,再基于切点生成曲线:

func drawLineBetweenCircles(center1: CGPoint, center2: CGPoint, circleRadius: CGFloat, curveOffset: CGFloat = 30) {
    // 计算两个圆心的距离,避免重合报错
    let dx = center2.x - center1.x
    let dy = center2.y - center1.y
    let distance = sqrt(dx*dx + dy*dy)
    guard distance > 0 else { return }
    
    // 计算指向另一个圆心的单位向量
    let unitDirX = dx / distance
    let unitDirY = dy / distance
    
    // 计算两个圆上的切点(曲线的起点和终点)
    let point1 = CGPoint(x: center1.x + unitDirX * circleRadius, y: center1.y + unitDirY * circleRadius)
    let point2 = CGPoint(x: center2.x - unitDirX * circleRadius, y: center2.y - unitDirY * circleRadius)
    
    // 用切点计算曲线控制点(和方案1逻辑一致)
    let midPoint = CGPoint(x: (point1.x + point2.x)/2, y: (point1.y + point2.y)/2)
    let perpendicularX = -unitDirY
    let perpendicularY = unitDirX
    let controlPoint = CGPoint(x: midPoint.x + perpendicularX * curveOffset, y: midPoint.y + perpendicularY * curveOffset)
    
    let path = UIBezierPath()
    path.move(to: point1)
    path.addQuadCurve(to: point2, controlPoint: controlPoint)
    path.flatness = 0.9
    
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    shapeLayer.strokeColor = UIColor.blue.cgColor
    shapeLayer.lineWidth = 5
    shapeLayer.fillColor = UIColor.clear.cgColor
    self.centerView.layer.addSublayer(shapeLayer)
}

额外提示:

如果需要更复杂的曲线(比如S型),可以换成三次贝塞尔曲线path.addCurve(to: point2, controlPoint1: cp1, controlPoint2: cp2),不过二次贝塞尔已经足够应对大多数圆形连接的场景啦。

内容的提问来源于stack exchange,提问作者Nikita Srivastava

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:48:27