SwiftUI路径-平滑连接两条线的曲线

sdnqo3pr  于 12个月前  发布在  Swift
关注(0)|答案(1)|浏览(80)

我有两行SwiftUI路径(见图)。我想用一个完美平滑的弧线连接这些,这样它看起来就像this图像中的讲话气泡尾巴。
我正在努力让它顺利连接。正如你在我的图片中看到的,它几乎是完美的,但线和弧(在右边)之间的第一个连接并不完美。
知道我哪里做错了吗我甚至把它画在纸上,我看不出哪个值不正确。

struct SpeechBubbleTail: Shape {
    private let radius: CGFloat
    init(radius: CGFloat = 10) {
        self.radius = radius
    }

    func path(in rect: CGRect) -> Path {
        Path { path in
            path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
            path.addLine(to: CGPoint(x: rect.minX + radius, y: rect.maxY - radius))
            
            path.addArc(
                center: CGPoint(x: rect.minX + ((radius / 2) * 1.5), y: rect.maxY - (radius * 1.5)),
                            radius: (radius / 2),
                            startAngle: Angle(degrees: 45),
                            endAngle: Angle(degrees: 180),
                            clockwise: false
                        )
                        
            path.addLine(to: CGPoint(x: rect.minX + ((radius / 2) * 0.5), y: rect.minY))
        }
    }
}
cnjp1d6j

cnjp1d6j1#

让我们将radius重命名为diameter,因为您使用radius / 2作为半径...
所以你有两条线,你想用一个圆弧连接。

  • (x: rect.maxX, y: rect.minY)(x: rect.minX + diameter, y: rect.maxY - diameter)的对角线,以及,
  • x = rect.minX + diameter / 4处的垂直线

观察结果:圆的中心 * 不能 * 在(x: rect.minX + ((diameter / 2) * 1.5), y: rect.maxY - (diameter * 1.5)
Desmos上的演示

突出显示的点是对角线的终点。圆圈根本没有穿过它。
不过不用担心,有一个方便的addArc(tangent1End:tangent2End:radius:transform:) API,它可以使用两条直线和一个半径,并生成一个与这两条直线相切的圆!

path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
// addArc will draw this line automatically, so you don't even need to draw it yourself
// path.addLine(to: CGPoint(x: rect.minX + diameter, y: rect.maxY - diameter))
path.addArc(
    // tangent1End is the intersection of the two lines when you extend them
    tangent1End: CGPoint(x: rect.minX + diameter / 4, y: rect.maxY - diameter / 4),
    tangent2End: CGPoint(x: rect.minX + ((diameter / 2) * 0.5), y: rect.minY),
    radius: diameter / 2)
path.addLine(to: CGPoint(x: rect.minX + ((diameter / 2) * 0.5), y: rect.minY))

这个post有一个非常好的图,显示了这个重载是如何工作的。
另请参阅Math.SE上的this post以了解其背后的数学原理。

相关问题