stevenpcurtis
stevenpcurtis

Reputation: 2001

Make programatic button equal width of storyboard button

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

Answers (1)

vacawama
vacawama

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:

  1. Create an outlet to your signUpButton:

    @IBOutlet weak var signUpButton: UIButton!
    
  2. Tell your programmatically created button that you don't want its frame to be turned into constraints:

    loginButton.translatesAutoresizingMaskIntoConstraints = false
    
  3. 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:

  1. 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)
    
  2. 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

Related Questions