Search code examples
swifttagssubviewuipangesturerecognizerfunc

func is reseting position of pan gesture


The func addBlackView is adding a black view everytime the func is called. The black view is connected a to uiPangesture the problem is evertyime the func addblackview is called the code is reseting the position of wherever the first black has been moved. You can see what is goin on in the gif below. I just want the 1st black view to not move and stay in the same position if a new black view is Called.

enter image description here

  import UIKit
class ViewController: UIViewController {

var image1Width2: NSLayoutConstraint!
var iHieght: NSLayoutConstraint!
var currentView = UIView()
override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(currentView)
    
    

    view.addSubview(button)
    button.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
        button.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
        button.widthAnchor.constraint(equalToConstant: 100),
        button.heightAnchor.constraint(equalToConstant: 80),
    ])
    button.addTarget(self,action: #selector(addBlackView),for: .touchUpInside)
   

}

let slider:UISlider = {
    let slider = UISlider(frame: .zero)
    return slider
}()

private lazy var button: UIButton = {
    let button = UIButton()
    button.backgroundColor = .blue
    button.setTitleColor(.white, for: .normal)
    button.setTitle("add", for: .normal)
    return button
}()

let blackView: UIView = {
    let view = UIView()
    view.backgroundColor = .black
  
    return view
}()
    var count = 0
    @objc
    private func addBlackView() {
        let newBlackView = UIView(frame: CGRect(x: 20, y: 20, width: 100, height: 100)) // whatever frame you want
        newBlackView.backgroundColor = .orange
        self.view.addSubview(newBlackView)
        self.currentView = newBlackView
        let recognizer = UIPanGestureRecognizer(target: self, action: #selector(moveView(_:)))
                   newBlackView.addGestureRecognizer(recognizer)
        newBlackView.isUserInteractionEnabled = true
        image1Width2 = newBlackView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.1)
        image1Width2.isActive = true
      iHieght = newBlackView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1)
        iHieght.isActive = true
        
        count += 1
        newBlackView.tag = (count)

        newBlackView.translatesAutoresizingMaskIntoConstraints = false
        newBlackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        newBlackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

    }


@objc private func moveView(_ recognizer: UIPanGestureRecognizer) {
    switch recognizer.state {
  
     
    case .changed:
        let translation = recognizer.translation(in: self.view)

        recognizer.view!.center = .init(x: recognizer.view!.center.x + translation.x,
                                        y: recognizer.view!.center.y + translation.y)
        recognizer.setTranslation(.zero, in: self.view)
    default:
        break
    }
}

    }
  

Solution

  • They always go back to the centre because you have constrained the black (orange) views to the centre:

    newBlackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    newBlackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    

    You shouldn't even be able to drag any of the views at all, but I guess setting center ignores constraints for some reason. Anyway, when you add a new view, UIKit calls view.setNeedsLayout/layoutIfNeeded somewhere down the line, and this causes all the views to realise "oh wait, I'm supposed to be constrained to the centre!" and snap back. :D

    If you want to keep using constraints, try storing the centre X and Y constraints of all the views in an array:

    var centerXConstraints: [NSLayoutConstraint] = []
    var centerYConstraints: [NSLayoutConstraint] = []
    

    And append to them when you add a new view:

    let yConstraint = newBlackView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
    let xConstraint = newBlackView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
    xConstraint.isActive = true
    yConstraint.isActive = true
    centerXConstraints.append(xConstraint)
    centerYConstraints.append(yConstraint)
    

    Then, rather than changing the center, change the constant of these constraints:

    let centerXConstraint = centerXConstraints[recognizer.view!.tag - 1]
    let centerYConstraint = centerYConstraints[recognizer.view!.tag - 1]
    centerXConstraint.constant += translation.x
    centerYConstraint.constant += translation.y
    

    Alternatively, and this is what I would do, just remove all your constraints, and translateAutoresizingMaskIntoConstraints = true. This way you can freely set your center.