iosswiftxcodeaddsubview

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


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)


    }
}

Solution

  • 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:

    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!
    
    }