paint-brush
Easy and flexible UIKit layout without Storyboards or Auto Layoutby@antonholmquist
3,345 reads
3,345 reads

Easy and flexible UIKit layout without Storyboards or Auto Layout

by Anton HolmquistApril 19th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

There is a small set of <a href="https://hackernoon.com/tagged/uikit" target="_blank">UIKit</a> standard methods that allow for very flexible <a href="https://hackernoon.com/tagged/layout" target="_blank">layout</a> and state management. The concept is similar to how <a href="https://facebook.github.io/react/" target="_blank">React</a> does rendering and state updates — a bit more about that later.

Company Mentioned

Mention Thumbnail
featured image - Easy and flexible UIKit layout without Storyboards or Auto Layout
Anton Holmquist HackerNoon profile picture

There is a small set of UIKit standard methods that allow for very flexible layout and state management. The concept is similar to how React does rendering and state updates — a bit more about that later.

So this is how I do it, starting with a UIViewController. Basically, I put all view layout logic in viewDidLayoutSubviews. This method is particularly suited for handling layouts since automatically called:

  1. When view is first loaded
  2. When the view frame changes
  3. When we call view.setNeedsLayout()

This is exactly what we want. Let’s at the code below. We create the button, add it to the view and put our layout logic in viewDidLayoutSubviews.

Whenever we want to re-layout or change the state we just update the controller state and then call view.setNeedsLayout again. I think this is so simple and powerful. It makes it easy to work with complex layouts and state changes.

So let’s look at another example where we actually have some state in the view controller - a tapCount that holds the number of times the button has been tapped. We also want to update the button title in viewDidLayoutSubviews to reflect the current count. Whenever the button is tapped the tapCount is increased and the view is updated.

This is very similar to how React works. You update the state and trigger a re-render. So the viewDidLayoutSubviews then corresponds to the React render method, and setting an instance variable and calling setNeedsLayout corresponds to React setState. This concept works very well in React and I believe it works just as well here.

For a UIView this works pretty much the same way, but using layoutSubviews instead of viewDidLayoutSubviews. Whenever you want to re-render just call setNeedsLayout.

Note: When calling setNeedsLayout the view is not updated immediately. It waits for the next update cycle. If you want to force an update you call layoutIfNeeded right after.

This is pretty much it it. I really like this way of doing layout and state management and I’ve been using it successfully in many projects.