I put off learning AutoLayout for a while when I first started developing macOS apps, mainly because developing a UI in Xcode has a bit of a learning curve and sometimes you just want to get an app out the door. It’s a really valuable skill that you should prioritize learning, especially if you want to localize your app.
It turns out that AutoLayout is not really something you can just pick up from tinkering around with Xcode, and sometimes the Apple docs can take a decent amount of time to glean what you actually need to get know to get started.
Anyways, let’s get up and running fast with some quick tips:
1. Use Stack Views
This is my main takeaway from the Apple docs, and it’s a good one. I tinkered with a lot of constraints before realizing that this is definitely what you should start out with if your views aren’t crazy complicated. You can find Stack Views in the object selector in Xcode (currently shown when you click the plus button in the top right and you have an Interface Builder view in focus). I prefer using the little “Embed In” button in the bottom right by the other Constraint buttons:
First select the views you want to group in a stack view and then click that button.
The main thing you’ll probably want to edit on your stack view is the spacing:
To get variable spacing between items, I’ve taken two different approaches that both work fine, depending on what outcome you desire:
- Add dummy views in with constraints that enforce certain widths or heights.
- Group some of the views in nested stack views, and give them different spacing.
A couple of notes about Stack Views:
- NSBox behaves pretty weird inside of stack views, so I tend to just avoid them.
- If you nest some stack views with certain UI elements, you may need to add a couple of constraints. Try using the dynamic constraints button for this and “Add Missing Constraints” for your “Selected View”. I don’t use this button any other time, as it seems to cause a lot more problems than it solves.
2. Properly use the “Add New Constraints” UI in IB
If you rely on stack views, you’ll still need to add constraints for the stack view to the parent view. If you don’t rely on stack views, you’re probably quite familiar with this button.
A few key notes here:
- If you delete the value for any of the “Spacing to nearest neighbor” constraints, it will set the “Standard” value for the spacing. This can save some time and thought about what to put for some of these values.
- If I have more UI elements to add below the one I’m setting constraints for, I don’t set the spacing to nearest neighbor below. When I add the next UI element, I set it’s constraint for spacing to nearest neighbor above.
- Avoid setting widths, because they can cause issues with localization. Xcode will give you warnings about this. After everything’s been added to your view and all of your spacing constraints are set, you can take a look at setting widths as noted in the next point.
3. Set widths and priorities for window width
In macOS, chances are you want your window to load with the width of the window fit to the content so that you don’t have a bunch of arbitrary white space. This is particularly noticeable if your window switches view sizes at all, like a prefs window that has different tabs.
To fix this, you can set two width constraints on your view that will determine your width. This view might be a stack view, or view that contains the stack view. Pick the width that you want your view to be in, and create the two constraints with that width. Leave one constraint as “Equal” and change the other one to “Greater than or equal”. Set the “Equal” one with a lower priority. What we’re telling AutoLayout to do is basically break the “Equal” constraint if necessary — if localization demands it.
Window height is typically not as much hassle, since height typically won’t vary as much with localization.
These points are what I learned from developing the Rectangle app. It’s open source, so you can take a look at it yourself on GitHub if you get stumped on anything. And it’s free so try it out if you haven’t already!