Search code examples
iosswiftuiviewcashapelayeruikit-dynamics

How to re-draw line connected between moveable two UIView


I would like to re-draw the line between two movable UIView, depending on the position of UIView.

So I found this. However, this method uses "Pan Gesture" to re-draw lines, depending on the position of the gesture.

enter image description here

Also found are setNeedsDisplay(), but this is a request to re-draw, not a real-time event function.

The way I want to find it is not to use gestures to redraw lines, but to re-draw lines in real time.

In a little bit more detail, I applied "UIColisionBehavior" to all the UIVviews I created. The UIView applied changes position as they are struck, and depending on the changed position, the line is being redrawn.

As if the UIView were moving in this way, the connected line was redrawn according to where it was moved:

enter image description here

Below is the code I'm experimenting with in the Playground. When you execute the code, you can see that the first connected purple line is connected to the falling UIView and does not fall off:

//: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport

class MoveAbleView : UIView {
    var outGoingLine : CAShapeLayer?
    var inComingLine : CAShapeLayer?

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func lineTo(connectedView: MoveAbleView) -> CAShapeLayer {
        let path = UIBezierPath()
        path.move(to: self.center)
        path.addLine(to: connectedView.center)

        let line = CAShapeLayer()
        line.path = path.cgPath
        line.lineWidth = 5
        line.strokeColor = UIColor.purple.cgColor
        connectedView.inComingLine = line
        outGoingLine = line
        return line
    }
}

class MyViewController : UIViewController {
    var dynamicAnimator = UIDynamicAnimator()
    var collisionBehavior = UICollisionBehavior()
    var gravityBehavior = UIGravityBehavior()

    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white
        self.view = view

        let viw = MoveAbleView(frame: CGRect(x: 100, y: 200, width: 50, height: 50))
        viw.backgroundColor = UIColor.red
        self.view.addSubview(viw)

        let viw2 = MoveAbleView(frame: CGRect(x: 300, y: 100, width: 50, height: 50))
        viw2.backgroundColor = UIColor.orange
        self.view.addSubview(viw2)

        let gravityViw = MoveAbleView(frame: CGRect(x: 100, y: 0, width: 50, height: 50))
        gravityViw.backgroundColor = UIColor.green
        self.view.addSubview(gravityViw)

        let gravityViw2 = MoveAbleView(frame: CGRect(x: 300, y: -200, width: 50, height: 50))
        gravityViw2.backgroundColor = UIColor.blue
        self.view.addSubview(gravityViw2)

        collisionBehavior.addItem(viw)
        collisionBehavior.addItem(viw2)
        collisionBehavior.addItem(gravityViw)
        collisionBehavior.addItem(gravityViw2)

        gravityBehavior.addItem(gravityViw)
        gravityBehavior.addItem(gravityViw2)

        dynamicAnimator.addBehavior(collisionBehavior)
        dynamicAnimator.addBehavior(gravityBehavior)
    self.view.layer.addSublayer(viw.lineTo(connectedView: viw2))
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

When UIView strikes and moves, how do you redraw a connected line in real time?


Solution

  • Actually, all what you need is another UIView to represent the lines and employ attachmentBehaviors. For instance, there is a line between two attached objects.

    class MyViewController : UIViewController {

    override func loadView() {
    
        let view = UIView()
    
    
        view.backgroundColor = .white
        self.view = view
        dynamicAnimator = UIDynamicAnimator(referenceView: view)
    
        let viw = MoveAbleView(frame: CGRect(x: 100, y: 200, width: 50, height: 50))
        viw.backgroundColor = UIColor.red
        self.view.addSubview(viw)
    
        let viw2 = MoveAbleView(frame: CGRect(x: 300, y: 200, width: 50, height: 50))
        viw2.backgroundColor = UIColor.orange
        self.view.addSubview(viw2)
    
        let gravityViw = MoveAbleView(frame: CGRect(x: 100, y: 0, width: 50, height: 50))
        gravityViw.backgroundColor = UIColor.green
        self.view.addSubview(gravityViw)
    
    
    
        let line1 = MoveAbleView(frame: CGRect(x: 125, y: 225, width: 200, height: 10))
        line1.backgroundColor = UIColor.purple
        self.view.addSubview(line1)
    
    
        let l1 =    UIAttachmentBehavior.init(item: viw, offsetFromCenter: UIOffset.zero, attachedTo: line1, offsetFromCenter: UIOffset.init(horizontal: -100, vertical: 0))
        let l2 =    UIAttachmentBehavior.init(item: viw2, offsetFromCenter: UIOffset.zero, attachedTo: line1, offsetFromCenter: UIOffset.init(horizontal: 100, vertical: 0))
    
        collisionBehavior.addItem(viw)
        collisionBehavior.addItem(viw2)
        collisionBehavior.addItem(gravityViw)
    
    
        gravityBehavior.addItem(gravityViw)
    
         dynamicAnimator.addBehavior(l1)
         dynamicAnimator.addBehavior(l2)
    
        dynamicAnimator.addBehavior(collisionBehavior)
        dynamicAnimator.addBehavior(gravityBehavior)
    
       }
    
    
      }
    

    enter image description here