Preefix
Preefix

Reputation: 273

Why is my second button behaving different when using auto layout constraints?

I can not figure out why my button is behaving different when using auto layout constraints programmatically.

When setting the view that holds my cancelBtn every thing is working fine:

 let cancelBtnView = TriangularView(frame: CGRect(x: 0, y: 0, width: 300, height: 150))

 let cancelBtn = UIButton()
 cancelBtnView.addSubview(cancelBtn)
 cancelBtn.titleLabel!.font = UIFont.fontAwesome(ofSize: 35, style: .regular)
 cancelBtn.setTitle(String.fontAwesomeIcon(name: .times), for: .normal)
 cancelBtn.frame = CGRect(x: cancelBtnView.bounds.width / 16, y: cancelBtnView.bounds.height / 2 ,width: 55, height: 55)

I get the following layout:

enter image description here

When setting up the view for my doneBtn I get a different output:

let doneBtnView = TriangularView()

 doneBtnView.translatesAutoresizingMaskIntoConstraints = false
 doneBtnView.widthAnchor.constraint(equalToConstant: 300).isActive = true
 doneBtnView.heightAnchor.constraint(equalToConstant: 150).isActive = true
 doneBtnView.trailingAnchor.constraint(equalTo: actionButtonView.trailingAnchor).isActive = true
 doneBtnView.bottomAnchor.constraint(equalTo: actionButtonView.bottomAnchor).isActive = true

 let doneBtn = UIButton()
 doneBtnView.addSubview(doneBtn)
 doneBtn.titleLabel!.font = UIFont.fontAwesome(ofSize: 35, style: .regular)
 doneBtn.setTitle(String.fontAwesomeIcon(name: .check), for: .normal)

  doneBtn.translatesAutoresizingMaskIntoConstraints = false
  doneBtn.widthAnchor.constraint(equalToConstant: 55).isActive = true
  doneBtn.heightAnchor.constraint(equalToConstant: 55).isActive = true
  doneBtn.leadingAnchor.constraint(equalTo: doneBtnView.leadingAnchor, constant:    doneBtnView.bounds.width / 16).isActive = true
 doneBtn.bottomAnchor.constraint(equalTo: doneBtnView.bottomAnchor, constant: doneBtnView.bounds.height / 2).isActive = true

Setting the constraints for my doneBtn programmatically I get the following:

enter image description here

The constraints for the doneBtnView are set programmatically because I want to pin it to the bottom right of its superview.

Upvotes: 0

Views: 31

Answers (1)

vacawama
vacawama

Reputation: 154523

Your problem is that you are looking at the bounds of the other view when setting your constraint for your doneBtn, but those bounds will not have been set yet because layout has not happened. In general, it is a bad idea to combine frame/bounds and constraints.

This can be done, but not with anchors. Try the following NSLayoutConstraints:

NSLayoutConstraint(item: doneBtn, attribute: .leading, relatedBy: .equal,
    toItem: doneBtnView, attribute: .trailing, multiplier: 1/16, constant: 0).isActive = true
    
NSLayoutConstraint(item: doneBtn, attribute: .top, relatedBy: .equal,
    toItem: doneBtnView, attribute: .bottom, multiplier: 1/2, constant: 0).isActive = true

and then set the width and height using anchors:

doneBtn.widthAnchor.constraint(equalToConstant: 55).isActive = true
doneBtn.heightAnchor.constraint(equalToConstant: 55).isActive = true

Note: Because we're using the .trailing and .bottom constraints to represent width and height, it might be necessary to put doneBtnView into a container view of the same size because the values will be in the coordinate system of the parent view. By making the parent view the exact same size, width will be equal to the trailing constraint, and height will be equal to the bottom constraint.

Upvotes: 1

Related Questions