Мне удалось создать синюю линию, как в Xcode, но как бы вы узнали, когда конечная точка линии перетаскивается и отпускается над другими метками или кнопками, чтобы можно было установить соединение?
код
class ViewController: UIViewController {
@IBOutlet var label: UILabel!
@IBOutlet var label2: UILabel!
private lazy var lineShape: CAShapeLayer = {
var color = hexStringToUIColor(hex: "#5DBCD2")
let lineShape = CAShapeLayer()
lineShape.strokeColor = UIColor.blue.cgColor
lineShape.fillColor = color.cgColor
lineShape.lineWidth = 2.0
return lineShape
}()
private var panGestureStartPoint: CGPoint = .zero
private lazy var panRecognizer: UIPanGestureRecognizer = {
return UIPanGestureRecognizer(target: self, action: #selector(panGestureCalled(_:)))
}()
override func viewDidLoad() {
super.viewDidLoad()
self.label.addGestureRecognizer(panRecognizer)
}
@objc func panGestureCalled(_: UIPanGestureRecognizer) {
let currentPanPoint = panRecognizer.location(in: self.view)
switch panRecognizer.state {
case .began:
panGestureStartPoint = currentPanPoint
self.view.layer.addSublayer(lineShape)
case .changed:
let linePath = UIBezierPath()
linePath.move(to: panGestureStartPoint)
linePath.addLine(to: currentPanPoint)
lineShape.path = linePath.cgPath
lineShape.path = CGPath.barbell(from: panGestureStartPoint, to: currentPanPoint, barThickness: 2.0, bellRadius: 6.0)
case .ended:
lineShape.path = nil
lineShape.removeFromSuperlayer()
default: break
}
}
func hexStringToUIColor (hex:String) -> UIColor {
var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
if (cString.hasPrefix("#")) {
cString.remove(at: cString.startIndex)
}
if ((cString.count) != 6) {
return UIColor.gray
}
var rgbValue:UInt32 = 0
Scanner(string: cString).scanHexInt32(&rgbValue)
return UIColor(
red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
alpha: CGFloat(1.0)
)
}
}
extension CGPath {
class func barbell(from start: CGPoint, to end: CGPoint, barThickness proposedBarThickness: CGFloat, bellRadius proposedBellRadius: CGFloat) -> CGPath {
let barThickness = max(0, proposedBarThickness)
let bellRadius = max(barThickness / 2, proposedBellRadius)
let vector = CGPoint(x: end.x - start.x, y: end.y - start.y)
let length = hypot(vector.x, vector.y)
if length == 0 {
return CGPath(ellipseIn: CGRect(origin: start, size: .zero).insetBy(dx: -bellRadius, dy: -bellRadius), transform: nil)
}
var yOffset = barThickness / 2
var xOffset = sqrt(bellRadius * bellRadius - yOffset * yOffset)
let halfLength = length / 2
if xOffset > halfLength {
xOffset = halfLength
yOffset = sqrt(bellRadius * bellRadius - xOffset * xOffset)
}
let jointRadians = asin(yOffset / bellRadius)
let path = CGMutablePath()
path.addArc(center: .zero, radius: bellRadius, startAngle: jointRadians, endAngle: -jointRadians, clockwise: false)
path.addArc(center: CGPoint(x: length, y: 0), radius: bellRadius, startAngle: .pi + jointRadians, endAngle: .pi - jointRadians, clockwise: false)
path.closeSubpath()
let unitVector = CGPoint(x: vector.x / length, y: vector.y / length)
var transform = CGAffineTransform(a: unitVector.x, b: unitVector.y, c: -unitVector.y, d: unitVector.x, tx: start.x, ty: start.y)
return path.copy(using: &transform)!
}
}
Код выше повторяет анимацию GIF. Я использовал приведенные ниже вопросы, чтобы создать его, если это поможет.
Нарисуйте линию, которая может растягиваться, как редактор Xcode помощник в Swift
Как воспроизвести эту синюю линию перетаскивания Xcode
Я думаю, что ответ на вышеупомянутый вопрос, но я не могу разобраться с этим, поскольку это для MacOS, а не iOS.
Любая помощь очень ценится
UPDATE
Из действительно хороших ответов я добавил приведенный ниже код в AddedPanGesture (). Это не окончательная версия кода.
case .changed:
let linePath = UIBezierPath()
linePath.move(to: panGestureStartPoint)
linePath.addLine(to: currentPanPoint)
lineShape.path = linePath.cgPath
lineShape.path = CGPath.barbell(from: panGestureStartPoint, to: currentPanPoint, barThickness: 2.0, bellRadius: 6.0)
let labels = [label2, label3]
for labelPoint in labels {
let point = panRecognizer.location(in: labelPoint)
if labelPoint!.layer.contains(point){
labelPoint!.layer.borderWidth = 10
labelPoint!.layer.borderColor = UIColor.green.cgColor
} else {
labelPoint!.layer.borderWidth = 0
labelPoint!.layer.borderColor = UIColor.clear.cgColor
}
}
case .ended:
let labels = [label2, label3]
for labelPoint in labels {
let point = panRecognizer.location(in: labelPoint)
if labelPoint!.layer.contains(point){
labelPoint!.layer.borderWidth = 2
labelPoint!.layer.borderColor = UIColor.green.cgColor
} else {
lineShape.path = nil
lineShape.removeFromSuperlayer()
labelPoint!.layer.borderWidth = 0
labelPoint!.layer.borderColor = UIColor.clear.cgColor
}
}
Если есть способ получше, мне бы понравился ввод.
Спасибо!