首先創建一個路徑開始於一個支架(0,0),並結束於(1,0)。然後應用仿射變換來移動,縮放和旋轉路徑以跨越您設計的端點。它需要將(0,0)轉換爲您的起點和(1,0)到您的終點。創建高效的轉換需要一些三角學,但我已經做了功課你:
extension UIBezierPath {
class func brace(from start: CGPoint, to end: CGPoint) -> UIBezierPath {
let path = self.init()
path.move(to: .zero)
path.addCurve(to: CGPoint(x: 0.5, y: -0.1), controlPoint1: CGPoint(x: 0, y: -0.2), controlPoint2: CGPoint(x: 0.5, y: 0.1))
path.addCurve(to: CGPoint(x: 1, y: 0), controlPoint1: CGPoint(x: 0.5, y: 0.1), controlPoint2: CGPoint(x: 1, y: -0.2))
let scaledCosine = end.x - start.x
let scaledSine = end.y - start.y
let transform = CGAffineTransform(a: scaledCosine, b: scaledSine, c: -scaledSine, d: scaledCosine, tx: start.x, ty: start.y)
path.apply(transform)
return path
}
}
結果:
這是我用來做演示整個斯威夫特遊樂場:
import UIKit
import PlaygroundSupport
extension UIBezierPath {
class func brace(from start: CGPoint, to end: CGPoint) -> UIBezierPath {
let path = self.init()
path.move(to: .zero)
path.addCurve(to: CGPoint(x: 0.5, y: -0.1), controlPoint1: CGPoint(x: 0, y: -0.2), controlPoint2: CGPoint(x: 0.5, y: 0.1))
path.addCurve(to: CGPoint(x: 1, y: 0), controlPoint1: CGPoint(x: 0.5, y: 0.1), controlPoint2: CGPoint(x: 1, y: -0.2))
let scaledCosine = end.x - start.x
let scaledSine = end.y - start.y
let transform = CGAffineTransform(a: scaledCosine, b: scaledSine, c: -scaledSine, d: scaledCosine, tx: start.x, ty: start.y)
path.apply(transform)
return path
}
}
class ShapeView: UIView {
override class var layerClass: Swift.AnyClass { return CAShapeLayer.self }
lazy var shapeLayer: CAShapeLayer = { self.layer as! CAShapeLayer }()
}
class ViewController: UIViewController {
override func loadView() {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 600, height: 200))
view.backgroundColor = .white
for (i, handle) in handles.enumerated() {
handle.autoresizingMask = [ .flexibleTopMargin, .flexibleTopMargin, .flexibleBottomMargin, .flexibleRightMargin ]
let frame = CGRect(x: view.bounds.width * 0.1 + CGFloat(i) * view.bounds.width * 0.8 - 22, y: view.bounds.height/2 - 22, width: 44, height: 44)
handle.frame = frame
handle.shapeLayer.path = CGPath(ellipseIn: handle.bounds, transform: nil)
handle.shapeLayer.lineWidth = 2
handle.shapeLayer.lineDashPattern = [2, 6]
handle.shapeLayer.lineCap = kCALineCapRound
handle.shapeLayer.strokeColor = UIColor.blue.cgColor
handle.shapeLayer.fillColor = nil
view.addSubview(handle)
let panner = UIPanGestureRecognizer(target: self, action: #selector(pannerDidFire(panner:)))
handle.addGestureRecognizer(panner)
}
brace.shapeLayer.lineWidth = 2
brace.shapeLayer.lineCap = kCALineCapRound
brace.shapeLayer.strokeColor = UIColor.black.cgColor
brace.shapeLayer.fillColor = nil
view.addSubview(brace)
setBracePath()
self.view = view
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setBracePath()
}
private let handles: [ShapeView] = [
ShapeView(),
ShapeView()
]
private let brace = ShapeView()
private func setBracePath() {
brace.shapeLayer.path = UIBezierPath.brace(from: handles[0].center, to: handles[1].center).cgPath
}
@objc private func pannerDidFire(panner: UIPanGestureRecognizer) {
let view = panner.view!
let offset = panner.translation(in: view)
panner.setTranslation(.zero, in: view)
var center = view.center
center.x += offset.x
center.y += offset.y
view.center = center
setBracePath()
}
}
let vc = ViewController()
PlaygroundPage.current.liveView = vc.view
您可以在線的末端添加四分之一的橢圓以獲得完美的曲線。 – Khundragpan
謝謝你的回答,你能舉一個例子來說明你的意思嗎? – Imbue