Swift Update Constraint
The issue is that you're adding a new constraint that conflicts with the existing constraint.
You have a few options:
Effective in iOS 8, you can set the
active
property tofalse
for a constraint before you add a new constraint.In iOS versions prior to 8, you would want to remove the old constraints before adding new constraints.
-
Ideally, it's best to not have to activate/deactivate (or, worse, add and remove) constraints, but rather just modify the
constant
property of a single constraint. For example in Swift 3/4:class ViewController: UIViewController { private var xConstraint: NSLayoutConstraint! private var yConstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() let label = UILabel() label.text = "x" label.translatesAutoresizingMaskIntoConstraints = false view.addSubview(label) // I don't really need to save references to these, so these are local variables let widthConstraint = label.widthAnchor.constraint(equalToConstant: 50) let heightConstraint = label.heightAnchor.constraint(equalToConstant: 50) // but since I'll be modifying these later, these are class properties xConstraint = label.centerXAnchor.constraint(equalTo: view.centerXAnchor) yConstraint = label.centerYAnchor.constraint(equalTo: view.centerYAnchor) NSLayoutConstraint.activate([widthConstraint, heightConstraint, xConstraint, yConstraint]) let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:))) view.addGestureRecognizer(pan) } private var originalCenter: CGPoint! @objc func handlePan(_ gesture: UIPanGestureRecognizer) { if gesture.state == .began { originalCenter = CGPoint(x: xConstraint.constant, y: yConstraint.constant) } let translation = gesture.translation(in: gesture.view!) xConstraint.constant = originalCenter.x + translation.x yConstraint.constant = originalCenter.y + translation.y } }
When the desired effect can be achieved by modifying the
constant
of the constraint, that's generally best.
For Swift 2 syntax, see previous revision of this answer.
stack
Updated on June 20, 2020Comments
-
stack almost 4 years
I added the constraint to the buttons created in my
UIView
func CreateButtonWithIndex(index:Int) { newButton.setTranslatesAutoresizingMaskIntoConstraints(false) self.view.addSubview(newButton) let newButtonConstraintL = NSLayoutConstraint(item: newButton, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50) let newButtonConstraintH = NSLayoutConstraint(item: newButton, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50) var newButtonConstraintX = NSLayoutConstraint(item: newButton, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: CGFloat(riga)) var newButtonConstraintY = NSLayoutConstraint(item: newButton, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: CGFloat(colonna)) view.addConstraints([newButtonConstraintX,newButtonConstraintY,newButtonConstraintH,newButtonConstraintL]) var pan = UIPanGestureRecognizer(target:self, action:"pan:") pan.maximumNumberOfTouches = 2 pan.minimumNumberOfTouches = 1 newButton.addGestureRecognizer(pan) } func pan(rec:UIPanGestureRecognizer) { case .Ended: if let subview = selectedView { if let button = rec.view as? UIButton { if let title = button.titleForState(.Normal){ button.setTranslatesAutoresizingMaskIntoConstraints(false) let line = Float(p.x % snapX) let column = Float(p.x % snapY) let constraintL = NSLayoutConstraint(item: button, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50) let constraintH = NSLayoutConstraint(item: button, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50) var constraint2 = NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: CGFloat(line)) var constraint3 = NSLayoutConstraint(item: button, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: CGFloat(column)) view.addConstraints([constraint2,constraint3,constraintL.constraintH]) } } } }
In My Project my users can move these buttons and then I tried to add more constraints to the buttons recognized but I just get an endless error constraint
"<NSLayoutConstraint:0x7f8e5a4e9450 UIButton:0x7f8e5a644f60'Button6'.centerX == UIView:0x7f8e5a648bc0.centerX - 120>", "<NSLayoutConstraint:0x7f8e5a5be040 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7f8e5a648bc0(736)]>", "<NSAutoresizingMaskLayoutConstraint:0x7f8e5a5be1f0 h=-&- v=-&- 'UIView-Encapsulated-Layout-Left' H:|-(0)-[UIView:0x7f8e5a648bc0] (Names: '|':UITransitionView:0x7f8e5a5a8190 )>", "<NSAutoresizingMaskLayoutConstraint:0x7f8e5a5b53b0 h=--& v=--& UIButton:0x7f8e5a644f60'Button6'.midX == + 200>"
Will attempt to recover by breaking constraint
"<NSLayoutConstraint:0x7f8e5a4e9450 UIButton:0x7f8e5a644f60'Button6'.centerX == UIView:0x7f8e5a648bc0.centerX - 120>" "<NSLayoutConstraint:0x7f8e5a4e9510 UIButton:0x7f8e5a644f60'Button6'.centerY == UIView:0x7f8e5a648bc0.centerY - 40>", "<NSLayoutConstraint:0x7f8e5a5be1a0 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7f8e5a648bc0(414)]>", "<NSAutoresizingMaskLayoutConstraint:0x7f8e5a5be240 h=-&- v=-&- 'UIView-Encapsulated-Layout-Top' V:|-(0)-[UIView:0x7f8e5a648bc0] (Names: '|':UITransitionView:0x7f8e5a5a8190 )>", "<NSAutoresizingMaskLayoutConstraint:0x7f8e5a5b82d0 h=--& v=--& UIButton:0x7f8e5a644f60'Button6'.midY == + 189>"
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7f8e5a4e9510 UIButton:0x7f8e5a644f60'Button6'.centerY == UIView:0x7f8e5a648bc0.centerY - 40>
... should I update newButtonConstraintX / Y but I'm not understanding how I can do this ?
-
Chanchal Warde almost 7 yearsHi @Rob, I am using the same approach. I have added constraints programmatically and now updating constants, but it's not updating view at.
-
Chanchal Warde almost 7 yearsNot updating frame of view .
-
Chanchal Warde almost 7 yearsI tried it with connecting constraints from storyboard and changing its constants from IBOutlet is working fine.