Search code examples
iosswiftautolayoutnslayoutconstraintvisual-format-language

Programmatically retrieve the width and height of a UIView using Auto Layout and NSLayoutConstraints?


How do you get the width and height of a UIView who's size and position are set using Auto Layout and Apple's Visual Format Language?

Here's the code (view is just the variable from UIViewController):

// Create and add the view
var stageView = UIView()
stageView.setTranslatesAutoresizingMaskIntoConstraints(false) // Since I'm using Auto Layout I turn this off
view.addSubview(stageView)

// Create and add constraints to the containing view
let viewsDictionary = ["stageView":stageView]
let horizontalConstraints: NSArray = NSLayoutConstraint.constraintsWithVisualFormat("H:|-150-[stageView]-150-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
let verticalConstraints: NSArray = NSLayoutConstraint.constraintsWithVisualFormat("V:|-100-[stageView]-150-|", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: viewsDictionary)
view.addConstraints(horizontalConstraints)
view.addConstraints(verticalConstraints)        
println("stageView.frame=\(stageView.frame)")

and got:

stageView.frame=(0.0,0.0,0.0,0.0)

so I tried:

let fittingSize = stageView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
println("fittingSize=\(fittingSize)")

and got:

fittingSize=(0.0,0.0)

I can't seem to find a way to get the size. I'm able to add subviews to stageView that place just fine using Auto Layout and Visual Format Language, but I can't get width and height for stageView which I need to further position those subviews.

Any ideas?


Solution

  • You have a few options:

    You can force the layout engine to size the views immediately by calling setNeedsLayout and then call layoutIfNeeded. This is not recommended because it's inefficient and any manual frames required for layout might not have been set yet. You can read more about this approach on my answer to this question.

    You can also wait until the subviews have been updated in the view controller:

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        println("stageView.frame = \(stageView.frame)")
    }
    

    If you want to know within a UIView subclass (or more often, a UITableViewCell subclass, you can check after layoutSubviews has run:

    override func layoutSubviews() {
        super.layoutSubviews()
        println("self.frame = \(self.frame)")
    }