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 ?
Select the height constraint from the Interface builder and take an outlet of it. So, when you want to change the height of the view you can use the below code. Method updateConstraints() is an instance method of UIView . It is helpful when you are setting the constraints programmatically.
Since multiplier is a read-only property and you can't change it, you need to replace the constraint with its modified clone.
When a property of your custom view changes in a way that would impact constraints, you can call this method to indicate that the constraints need to be updated at some point in the future. The system will then call updateConstraints() as part of its normal layout pass.
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 to false
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With