Is there a way to add subviews to Xcode without reseting the position of the last view added?

81 Views Asked by At

This is my code:

let newView = ImageView()
    newView.translatesAutoresizingMaskIntoConstraints = false
    newView.backgroundColor = .random()
    view.addSubview(newView)

    newView.widthAnchor.constraint(equalToConstant: 100).isActive = true
    newView.heightAnchor.constraint(equalToConstant: 100).isActive = true
    newView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    newView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

    let panGR = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
    panGR.delegate = self
    newView.addGestureRecognizer(panGR)

    let pinchGR = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(pinch:)))
    pinchGR.delegate = self
    newView.addGestureRecognizer(pinchGR)

    let rotateGR = UIRotationGestureRecognizer(target: self, action: #selector(handleRotate(rotate:)))
    rotateGR.delegate = self
    newView.addGestureRecognizer(rotateGR)

Every time the button is pressed, it runs this code. However, all of the subviews keep reseting their position.

This is the code for 'handlePan':

@objc func handlePan(_ gestureRecognizer : UIPanGestureRecognizer){
    if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
        let translation = gestureRecognizer.translation(in: self.view)
        gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)

        gestureRecognizer.setTranslation(CGPoint.zero, in: self.view)


    }
}
1

There are 1 best solutions below

6
Alex On BEST ANSWER

Because you set a constraints at custom view creating.

After custom view was added to superview, you change its position by dragging - but you do it just change center property. Ok.

When you did added new custom view to your superview - will be executed layout subviews. And all your subviews positions will be reseted according initial constraints.

You need:

  • Either do not use constraints in your subviews
  • Either In your handlePan(_ gestureRecognizer : UIPanGestureRecognizer) func change centerXAnchor,centerYAnchor constraint values, not center property. Because after any layout subviews, their positions will be set to original.

    let newView = UIImageView.init(frame: .init(x: 0, y: 0, width: 100, height: 100))
    newView.translatesAutoresizingMaskIntoConstraints = false
    newView.isUserInteractionEnabled = true
    newView.backgroundColor = UIColor.random
    view.addSubview(newView)
    
    // newView.widthAnchor.constraint(equalToConstant: 100).isActive = true
    // newView.heightAnchor.constraint(equalToConstant: 100).isActive = true
    // newView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    // newView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    
    let panGR = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
    panGR.delegate = self
    newView.addGestureRecognizer(panGR)
    

This code works good.

Version with constraints:

@IBAction func addView() {
    let newView = CustomView.init()
    newView.translatesAutoresizingMaskIntoConstraints = false
    newView.isUserInteractionEnabled = true
    newView.backgroundColor = UIColor.random
    view.addSubview(newView)

    newView.widthAnchor.constraint(equalToConstant: 100).isActive = true
    newView.heightAnchor.constraint(equalToConstant: 100).isActive = true
    newView.centerXConstraint = newView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
    newView.centerYConstraint = newView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
    newView.centerXConstraint.isActive = true
    newView.centerYConstraint.isActive = true

    let panGR = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
    panGR.delegate = self
    newView.addGestureRecognizer(panGR)
}

@objc func handlePan(_ gestureRecognizer : UIPanGestureRecognizer){
    if gestureRecognizer.state == .began || gestureRecognizer.state == .changed,
        let view = gestureRecognizer.view as? CustomView,
        let centerXConstraint = view.centerXConstraint,
        let centerYConstraint = view.centerYConstraint {
        let translation = gestureRecognizer.translation(in: self.view)
        let x = centerXConstraint.constant + translation.x
        let y = centerYConstraint.constant + translation.y
        centerXConstraint.constant = x
        centerYConstraint.constant = y
        gestureRecognizer.setTranslation(CGPoint.zero, in: self.view)
    }
}

Add constraint variables in your custom class

class CustomView: UIView {
    var centerXConstraint: NSLayoutConstraint!
    var centerYConstraint: NSLayoutConstraint!

}