From the blog

and How Stackable Can Help

Six Tricky Layouts in Swift

…and how Stackable can help

Some common iOS interface design patterns are way easier to talk about than they are to develop. Adaptable, maintainable code should be as easy to write and tinker with as it is to express in a conversation with your designer.

I want to cover six tricky layouts that I encounter frequently, and how my library Stackable can help solve these problems.

Stackable is a delightful and declarative set of utilities for UIStackView. It closely mirrors how my designer thinks about and communicates layout.

1. Variable-Sized Content

Contacts App with variable font size

It is NEVER safe to assume that a design will fit nicely on one screen. It wont. Trust me. Make sure your development team understands this. Your designers, too. Heck, everyone else at your org. iPhones come in multiple screen sizes and users can choose their font size.

Everything should scroll. Scrolling is free. Users are used to this and comfortable with this. Even if a page doesn’t scroll, they’ll scroll anyway just to check.

All of your screens should be prepared to scroll in the case that the content overflows the screen.

Unfortunately, this is sort of annoying to code with UIKit. Mostly due to UIStackView being a nonrendering UIView subclass.

Anyway, we’ve got it all figured out for you. Use ScrollingStackView. It is a UIStackView in a UIScrollView that will prefer to be the size of your screen until its content overflows. Then it starts scrolling.

2. Variable Hairlines

Settings App includes 3 different hairline insets within one square inch of UI

Hairlines are all over iOS. Design wise, they seem to have their own rules. They can overflow margins. They can be inset. They can be asymmetrical. They can appear after cells, before sections, around views. They can be thick or thin and different colors. They can be a whole lot of development pain and noise for 1 pixel of interface.

Don’t let hairlines dominate your layout code. They don’t dominate your conversations with your designer.

Stackable has a suite of tools to help concisely get the functionality you need and move on.

        .outset(to: view),
    UIStackView.stackable.hairlines(around: cells)
        .inset(by: .left(10))
  • inset(by:) allows you to move any view around relative to its normal UIStackView layout.
  • outset(to:) allows you to break outside of the bounds of the UIStackView and apply constraints against some other ancestor.

3. Custom and Conditional Spacing

Spacing rules often gets lost in the cracks. Implied, but not vocalized by your designer. Spaces are used to visually separate two items or groups. Their size depends on what they are separating. Their need is dependent on which possible combination of elements are visible on screen.

UIStackView started with a very limited spacing API. You got one space per stack, and that was applied between everything. Later, they introduced setCustomSpacing(_:after:), which allowed you to apply a different value dependent on the visibility of some subview. This was a tiny step in the right direction, but still wildly limited.

Conditional spacing is implicitly all over designs. Spaces between groups of cells. Spaces between this view and that view. Spaces that should or shouldn’t be there depending on what data you have. Spaces that should be at least this much but no more than that much.

Stackable has you covered. Custom spacing can be applied and will monitor the visibility of any view(s), showing or hiding to match. Spaces can be fixed or flexible.

    viewB, viewB 20),
    viewC, viewD, 20),
    viewE, viewE, viewF, 20),
  • Spaces can be articulated using numbers (fixed space) or ranges of numbers (flexible spaces)
  • Spaces immediately following a view will implicitly monitor the visibility of that view, and update accordingly.
  • .space(after:) and space(before: are spaces that explicitly monitor the visibility of some view.
  • .space(between:) will monitor the visibility of two views, and will only be visible if both views are.

4. Variable Alignment

Contacts App includes a mix of center-aligned and left-aligned content

Similar to custom spacing, UIStackView can be clunky when trying to adjust the alignment of one or two subviews. Common practice is to wrap your view in a container view, apply constraints, remember to toggle the visibility of your container if you want to hide the view itself, yadda yadda. It’s a bunch of noise.

Stackable includes a clean .aligned() API. Set it and move on.

        .inset(by: .right(10),

5. Aligning Margins

Layout margins in UIKit are a trip. You set them and hope that iOS doesn’t overwrite them. If you want a clean margin extending through all your subviews, you’ve got work to do. You’ll need to pump in your desired margin into all of your subviews, taking offset coordinate spaces into account. Monitor for changes and repeat.

Designers don’t think about or communicate margins on a subview by subview basis. Its usually one big ol’ red line that gets fiddled with depending on the screen form factor.

Stackable includes tools to line up frames and margins and keep them in sync.

Take a group of settings cells, for example. They have their own background color that extends to the edge of the view, but their margins align with the layout of the view controller.

        .outset(to: view)           
        .margins(alignedWith: view)
  • outset(to:) allows you to align the cell edges (and thus, background color) extends to the horizontal edges of view
  • margins(alignedWith:) will update the .layoutMarginsGuide of cells to match and monitor the horizontal edges of view.layoutMarginsGuide

6. Variable Visibility

In Contacts App, the absence of some data hides related labels and decorations.

UI is populated by data. Optional data means optional UI. Optional UI means optional decoration, etc, etc.

Sometimes, this web of dependent-visibility can get quite complicated. Spacing, hairlines, borders, sections can all cascade based on what combination of UI end up on screen.

Stackable includes helper functionality to monitor the visibility of some view, and toggle another view’s visibility to match. In fact, this is how the hairline and spacing APIs work under the hood.

decoration.stackable.bindVisible(to: dataLabel)

Try Stackable!

Stop writing muddy code that does simple stuff. Spend your time collaborating with your designers and listening to your users.

Stackable will help you write cleaner, more articulate, and more consistent layout code. Give it a try and let us know what you think!

Leave a Reply

Your email address will not be published.