Quick update limit

I added a restriction on 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(px % snapX) let column = Float(px % 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 restrictions to the recognized buttons, but I just get an infinite error limit

  "<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 try to recover, violating the restriction

 "<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 try to recover, violating the restriction

 <NSLayoutConstraint:0x7f8e5a4e9510 UIButton:0x7f8e5a644f60'Button6'.centerY == UIView:0x7f8e5a648bc0.centerY - 40> 

... should I update newButtonConstraintX / Y, but I don't understand how to do this?

+8
autolayout ios8 swift
source share
3 answers

The problem is that you are adding a new constraint that conflicts with the existing constraint.

You have several options:

  • Effective in iOS 8, you can set the active property to false for a constraint before adding a new constraint.

  • In iOS versions prior to 8, you will need to remove the old restrictions before adding new restrictions.

  • Ideally, it’s better not to enable / disable (or, worse, add and remove) constraints, but simply modify the constant property for one 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 changing the constant limit, which is usually best.

For Swift 2 syntax, see the previous version of this answer .

+15
source share

Looks like you're just adding more and more restrictions. You cannot do this because they are clearly in conflict with each other. You basically say: "Put the view in position x = 1, x = 2, x = 3, x = 4 and x = 5."

You need to remove the old restrictions. You have two options.

  • Save the constraints in the array and remove these constraints from the view before adding new ones.

  • Or you keep a link to restrictions that change and adjust their properties.

Since your limitations simply differ in constant value, you should go for option 2.

Make newButtonConstraintX and newButtonConstraintY variable.

eg.

 class ViewController: UIViewController { var newButtonConstraintX: NSLayoutConstraint! var newButtonConstraintY: NSLayoutConstraint! func CreateButtonWithIndex(index:Int) { newButtonConstraintX = NSLayoutConstraint(item: newButton, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: CGFloat(riga)) newButtonConstraintY = NSLayoutConstraint(item: newButton, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: CGFloat(colonna)) /* ... */ } func pan(rec:UIPanGestureRecognizer) { /* ... */ newButtonConstraintX.constant = line newButtonConstraintY.constant = column button.layoutIfNeeded() } 
0
source share

Update Rob Reply to Swift 3:

 class ViewController: UIViewController { private var xConstraint: NSLayoutConstraint! private var yConstraint: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() let label = UILabel() label.text = "x" label.setTranslatesAutoresizingMaskIntoConstraints(false) view.addSubview(label) // I don't really need to save references to these, so these are local variables let widthConstraint = NSLayoutConstraint(item: drugToDrugView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 50) let heightConstraint = NSLayoutConstraint(item: drugToDrugView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 50) // but since I'll be modifying these later, these are class properties xConstraint = NSLayoutConstraint(item: drugToDrugView, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0) yConstraint = NSLayoutConstraint(item: drugToDrugView, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1.0, constant: 0) drugToDrugView.addConstraints([widthConstraint, heightConstraint, xConstraint, yConstraint]) let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan)) view.addGestureRecognizer(pan) } private var originalCenter: CGPoint! 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 view.setNeedsLayout() } 
0
source share

All Articles