我正在尝试创建一些可通过线连接的可拖动UIView。见下图:
我可以通过创建一个类来创建可拖动的圆圈,该类是UIView的子类并覆盖绘制函数
override func draw(_ rect: CGRect) {
let path = UIBezierPath(ovalIn: rect)
let circleColor:UIColor
switch group {
case .forehead:
circleColor = UIColor.red
case .crowsFeetRightEye:
circleColor = UIColor.green
case .crowsFeetLeftEye:
circleColor = UIColor.blue
}
circleColor.setFill()
path.fill()
}
然后为拖动添加平移手势识别器
func initGestureRecognizers() {
let panGR = UIPanGestureRecognizer(target: self, action: #selector(DragPoint.didPan(panGR:)))
addGestureRecognizer(panGR)
}
@objc func didPan(panGR: UIPanGestureRecognizer) {
if panGR.state == .changed {
self.superview!.bringSubview(toFront: self)
let translation = panGR.translation(in: self)
self.center.x += translation.x
self.center.y += translation.y
panGR.setTranslation(CGPoint.zero, in: self)
}
}
但是,我完全不知道如何在连接线上进行操作,并在拖动时将起点/终点点到相应的圆圈。有没有人可以帮助或指出我正确的方向?
答案 0 :(得分:6)
您希望CAShapeLayers
使用UIBezier
路径绘制圆圈之间的线条,然后在用户移动视图时更改路径。
这是一个展示实施的游乐场。您可以将其剪切并粘贴到游乐场中以查看它的实际效果。
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class CircleView : UIView {
var outGoingLine : CAShapeLayer?
var inComingLine : CAShapeLayer?
var inComingCircle : CircleView?
var outGoingCircle : CircleView?
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = self.frame.size.width / 2
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func lineTo(circle: CircleView) -> CAShapeLayer {
let path = UIBezierPath()
path.move(to: self.center)
path.addLine(to: circle.center)
let line = CAShapeLayer()
line.path = path.cgPath
line.lineWidth = 5
line.strokeColor = UIColor.red.cgColor
circle.inComingLine = line
outGoingLine = line
outGoingCircle = circle
circle.inComingCircle = self
return line
}
}
class MyViewController : UIViewController {
let circle1 = CircleView(frame: CGRect(x: 100, y: 100, width: 50, height: 50))
let circle2 = CircleView(frame: CGRect(x: 100, y: 200, width: 50, height: 50))
let circle3 = CircleView(frame: CGRect(x: 100, y: 300, width: 50, height: 50))
let circle4 = CircleView(frame: CGRect(x: 100, y: 400, width: 50, height: 50))
override func loadView() {
let view = UIView()
view.backgroundColor = .white
self.view = view
circle1.backgroundColor = .red
view.addSubview(circle1)
circle2.backgroundColor = .red
view.addSubview(circle2)
circle3.backgroundColor = .red
view.addSubview(circle3)
circle4.backgroundColor = .red
view.addSubview(circle4)
circle1.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(didPan(gesture:))))
circle2.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(didPan(gesture:))))
circle3.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(didPan(gesture:))))
circle4.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(didPan(gesture:))))
view.layer.addSublayer(circle1.lineTo(circle: circle2))
view.layer.addSublayer(circle2.lineTo(circle: circle3))
view.layer.addSublayer(circle3.lineTo(circle: circle4))
}
@objc func didPan(gesture: UIPanGestureRecognizer) {
guard let circle = gesture.view as? CircleView else {
return
}
if (gesture.state == .began) {
circle.center = gesture.location(in: self.view)
}
let newCenter: CGPoint = gesture.location(in: self.view)
let dX = newCenter.x - circle.center.x
let dY = newCenter.y - circle.center.y
circle.center = CGPoint(x: circle.center.x + dX, y: circle.center.y + dY)
if let outGoingCircle = circle.outGoingCircle, let line = circle.outGoingLine, let path = circle.outGoingLine?.path {
let newPath = UIBezierPath(cgPath: path)
newPath.removeAllPoints()
newPath.move(to: circle.center)
newPath.addLine(to: outGoingCircle.center)
line.path = newPath.cgPath
}
if let inComingCircle = circle.inComingCircle, let line = circle.inComingLine, let path = circle.inComingLine?.path {
let newPath = UIBezierPath(cgPath: path)
newPath.removeAllPoints()
newPath.move(to: inComingCircle.center)
newPath.addLine(to: circle.center)
line.path = newPath.cgPath
}
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
PlaygroundPage.current.needsIndefiniteExecution = true
答案 1 :(得分:0)
UIBezierPaths和CAShapeLayers可以解决此问题,但是有一种更简便的方法。
每次视图移动时调用该函数并使用设置图像 UIGraphicsImageRenderer。
func drawLines(viewOne: UIView, viewTwo: UIView) {
let rendered = UIGraphicsImageRenderer(bounds: view.bounds)
imageView.image = rendered.image(actions: { (ctx) in
ctx.cgContext.setLineWidth(2)
ctx.cgContext.strokeLineSegments(between: [viewOne.center, viewTwo.center])
}
})
}