No headache: auto layout tips in Interface Builder
Recent versions of Xcode and Interface Builder are great visual tools to build auto layout UIs.
I wrote previously how to setup your main views so that embedding properly respects safe areas on whatever device it’s being run on. The key thing: setup inner constraints towards VC.view to use superview margins. Easiest way to do this is to:
- add one UIView as direct child of VC.view
- setup constraints of that view so its edges are all connected to VC.view’s margins
- All your content then goes into that “real” content view and you are set
This will solve at least 90% of layouts you’ll ever need to do.
Don’t forget an older tip about setting priority 999 for some of the sides of realContentView.
Another great guideline: when you have a series of child sibling views inside a container, either horizontal or vertical, your job will be much easier if you prioritise making constraints among siblings and avoid superview as much as possible.
Between vertical siblings, it looks like this:
Few things:
- Make sure to use default (standard) spacing because then you follow HIG and app will generally look better.
- First sibling in a (vertical) row will have constraints to leading, top and trailing edges of the superview.
- The following child views will align each other.
- The last child will align to superview’s bottom edge.
- By doing this, you will have just one place to change spacing for all the children.
Or you can use UIStackView
for this, although I find that component useful only with repeating identical views. In all other cases it’s more trouble than it’s worth. Additionally in case you want to create a layout that autosizes per contentSizeCategory, then stack views can make that impossible, depending on the layout.
Speaking of dynamic type, always, always use Text styles for all your UILabel
, UITextField
, UITextView
etc. And make sure to set this “Automatically Adjusts Font” checkbox:
and make sure to set Lines: 0 so the text is fully visible regardless what content category size is used by end customer.
UIButton
sadly does not have this option, but you can enforce it for its titleLabel
:
You’ll need to include this simple extension somewhere in your code:
extension UIButton {
/// Allows automatic response on contentSize change (dynamic type)
@IBInspectable
var adjustsFontForContentSizeCategory: Bool {
set {
self.titleLabel?.adjustsFontForContentSizeCategory = newValue
}
get {
return self.titleLabel?.adjustsFontForContentSizeCategory ?? false
}
}
}
for that option to appear in Interface Builder.
For buttons, also make sure to use greaterThanOrEqual
height constraint:
Final tip for today: IB does not have easy ability to setup rounded corners that are so prevalent in many designs, especially for buttons and various containers. Thus many devs resort to using this in code:
textView.layer.borderWidth = 1
textView.layer.borderColor = UIColor.lightGrey.cgColor
textView.layer.cornerRadius = 4
You can use runtime attributes for this, in the Identity panel (rather strange place for it):
The code above is almost always followed by this file as well, to actually have those rounded corners rendered:
textView.layer.masksToBounds = true
This line is also not needed as the same thing is achieved by simply setting “Clips to bounds” on View subsection in the Attributes panel.