Use autolayout to your advantage. It can do all the heavy lifting for you.
Here is a UIViewController
that lays out 3 UILabels
, as you have in your screen shot, with no calculations. There are 3 UIView
subviews that are used to give the labels "padding" and set the background color. Each of those UIViews
has a UILabel
subview that just shows the text and nothing else.
All of the layout is done with autolayout in viewDidLoad
, which means no calculating ratios or frames and no KVO. Changing things like padding and compression/hugging priorities is a breeze. This also potentially avoids a dependency on an open source solution like TZStackView
. This is just as easily setup in interface builder with absolutely no code needed.
class StackViewController: UIViewController {
private let leftView: UIView = {
let leftView = UIView()
leftView.translatesAutoresizingMaskIntoConstraints = false
leftView.backgroundColor = .blueColor()
return leftView
}()
private let leftLabel: UILabel = {
let leftLabel = UILabel()
leftLabel.translatesAutoresizingMaskIntoConstraints = false
leftLabel.textColor = .whiteColor()
leftLabel.text = "A medium title"
leftLabel.textAlignment = .Center
return leftLabel
}()
private let middleView: UIView = {
let middleView = UIView()
middleView.translatesAutoresizingMaskIntoConstraints = false
middleView.backgroundColor = .redColor()
return middleView
}()
private let middleLabel: UILabel = {
let middleLabel = UILabel()
middleLabel.translatesAutoresizingMaskIntoConstraints = false
middleLabel.textColor = .whiteColor()
middleLabel.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
middleLabel.textAlignment = .Center
return middleLabel
}()
private let rightView: UIView = {
let rightView = UIView()
rightView.translatesAutoresizingMaskIntoConstraints = false
rightView.backgroundColor = .greenColor()
return rightView
}()
private let rightLabel: UILabel = {
let rightLabel = UILabel()
rightLabel.translatesAutoresizingMaskIntoConstraints = false
rightLabel.textColor = .whiteColor()
rightLabel.text = "OK"
rightLabel.textAlignment = .Center
return rightLabel
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(leftView)
view.addSubview(middleView)
view.addSubview(rightView)
leftView.addSubview(leftLabel)
middleView.addSubview(middleLabel)
rightView.addSubview(rightLabel)
let views: [String : AnyObject] = [
"topLayoutGuide" : topLayoutGuide,
"leftView" : leftView,
"leftLabel" : leftLabel,
"middleView" : middleView,
"middleLabel" : middleLabel,
"rightView" : rightView,
"rightLabel" : rightLabel
]
// Horizontal padding for UILabels inside their respective UIViews
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-(16)-[leftLabel]-(16)-|", options: [], metrics: nil, views: views))
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-(16)-[middleLabel]-(16)-|", options: [], metrics: nil, views: views))
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-(16)-[rightLabel]-(16)-|", options: [], metrics: nil, views: views))
// Vertical padding for UILabels inside their respective UIViews
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(6)-[leftLabel]-(6)-|", options: [], metrics: nil, views: views))
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(6)-[middleLabel]-(6)-|", options: [], metrics: nil, views: views))
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(6)-[rightLabel]-(6)-|", options: [], metrics: nil, views: views))
// Set the views' vertical position. The height can be determined from the label's intrinsic content size, so you only need to specify a y position to layout from. In this case, we specified the top of the screen.
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[topLayoutGuide][leftView]", options: [], metrics: nil, views: views))
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[topLayoutGuide][middleView]", options: [], metrics: nil, views: views))
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[topLayoutGuide][rightView]", options: [], metrics: nil, views: views))
// Horizontal layout of views
NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[leftView][middleView][rightView]|", options: [], metrics: nil, views: views))
// Make sure the middle view is the view that expands to fill up the extra space
middleLabel.setContentHuggingPriority(UILayoutPriorityDefaultLow, forAxis: .Horizontal)
middleView.setContentHuggingPriority(UILayoutPriorityDefaultLow, forAxis: .Horizontal)
}
}
Resulting view:
