1

I'm trying to understand constraints' logic and there is somethin I cannot find out...

I created a custom UIButton and add some constraints to change it's width and height and it's working fine. But I cannot find the new width and height values of the button. How can I get these values after constraints change them?

Here is my code...

import Foundation
import UIKit

class RoundedButton: UIButton {

    class func make (text:String, color:UIColor) -> RoundedButton {

        let button = self.buttonWithType(UIButtonType.System) as RoundedButton
        button.frame = CGRectMake(0, 0, 150, 40)
        button.layer.cornerRadius = 20
        button.layer.borderColor = color.CGColor
        button.layer.borderWidth = 2

        button.setTitle(text, forState: UIControlState.Normal)
        button.setTitleColor(color, forState: UIControlState.Normal)
        button.titleLabel?.font = UIFont(name: "OpenSans-Semibold", size: 14)
        return button
    }

    func resizeAndPlace(width:CGFloat, height:CGFloat)
    {
        self.setTranslatesAutoresizingMaskIntoConstraints(false)

        let widthCons = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: width)

        let heightCons = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: height)

        self.superview!.addConstraint(widthCons)
        self.superview!.addConstraint(heightCons)

        println(self.frame.width) // 150 and never changes
    }
}
Utku Demir
  • 37
  • 5
  • You don't need to add the constraints to the `superview` of the button since they only affect the button itself. `self.addConstraint ...` will suffice. – vacawama Jul 29 '15 at 14:55
  • It's giving me "The view hierarchy is not prepared for the constraint.." error when I don't add the constraints to the superview. – Utku Demir Jul 29 '15 at 17:09
  • are these the same constraints you show above? It worked for me. Or are you adding new constraints that place the button in the superview, for instance? – vacawama Jul 29 '15 at 17:18
  • Even easier than messing with adding constraints to views, you can just set the `active` property to `true`. For example, `widthCons.active = true`. – vacawama Jul 29 '15 at 17:23
  • "active = true" worked fine. What's difference between these methods? – Utku Demir Jul 29 '15 at 22:52
  • `active = true` is the new way as of IOS 8. The old way has been deprecated and will go away in the future. Use the old way to support older iOS. New way is easier because iOS figures out for you which views to add the constraints to. You can easily deactivate the constraints with `active = false`. You can activate an array of constraints by calling class method `NSLayoutConstraint.activateConstraints(c)` which is handy for constraints generated with the Visual Format Language. – vacawama Jul 29 '15 at 23:10

2 Answers2

3

The reason you aren't seeing the constraints take effect is that layout hasn't happened yet. If you call:

self.layoutIfNeeded()

immediately after setting the constraints, then the values will be reflected in the frame.

vacawama
  • 150,663
  • 30
  • 266
  • 294
1

There are a couple ways you can do this in your sample code. You could actually store the width and height variables from resizeAndPlace as properties in your RoundedButton class, but a better solution would be to store the constraints themselves and do widthConstraint.constant and heightConstraint.constant. Then when you want to change the constraints, you can just change the constants instead of removing the old constraints and adding new constraints.

Eric
  • 2,077
  • 17
  • 16