Reputation: 2001
I want to create constraints to make a button (made programmatically) equal to an existing button in a stackview.
I thought it best to do in view will appear so the layout is finished.
Unfortunately the following results in a crash - NSInvalidArgumentException Unknown layout attibute.
I have a storyboard constraint for the height of my signup button -
@IBOutlet weak var signupHeight: NSLayoutConstraint!
and then in view will appear:
loginStack.insertArrangedSubview(loginButton, at: 0)
loginButton.addConstraint(NSLayoutConstraint(item: loginButton, attribute: .height, relatedBy: .equal, toItem: signupHeight, attribute: .notAnAttribute, multiplier: 1, constant: 0))
Upvotes: 0
Views: 77
Reputation: 154731
I want to create constraints to make a button (made programmatically) equal to an existing button in a stackview.
You can do this. Constraints are made between 2 views or a view and a constant (such as 5
). In your case, you should be making the constraints between your two buttons. If your constant is the attribute of another view (such as its height), then you need to be using the form of constraint that takes 2 views and access the attribute that way.
The item in a constraint is a view (a subclass of UIView
like UIButton
or UILabel
). Your problem is that you have an @IBOutlet
to the button's height when you really need an @IBOutlet
to the button itself.
I thought it best to do in view will appear so the layout is finished.
No. If you are using constraints, you should set your constraints up early when you are constructing your view hierarchy (in viewDidLoad
for example) so that they're ready to do their thing when Auto Layout runs.
Here is what you need to do:
Create an outlet to your signUpButton
:
@IBOutlet weak var signUpButton: UIButton!
Tell your programmatically created button that you don't want its frame to be turned into constraints:
loginButton.translatesAutoresizingMaskIntoConstraints = false
Create and activate a constraint to make the heights of your buttons equal:
loginButton.heightAnchor.constraint(equalTo: signupButton.heightAnchor).isActive = true
This should be done after loginButton
has been added to the view hierarchy (ie. added to the stackView).
Notes:
I used layout anchors to create the constraint which are nice and concise. You could have done it this way:
NSLayoutConstraint(item: loginButton, attribute: .height,
relatedBy: .equal, toItem: signupButton,
attribute: .height, multiplier: 1, constant: 0)
I used .isActive = true
to activate the constraint. That is the recommended way to activate constraints. Instead of adding them to a view, you set their isActive
property to true
and Auto Layout adds the constraint to the proper view. This is better because it is frequently confusing which view a constraint should be added to. It would not work to add this constraint to one of the buttons, because it needs to be added to their common ancestor (ie. the stackView).
If you have multiple constraints you want to activate together, you can pass an array of constraints to the class function activate
of NSLayoutConstraint
:
For example:
NSLayoutConstraint.activate([widthConstraint, heightConstraint])
Upvotes: 1