In the beginning, there was CGRectMake. It was hideous.

_badge.frame = CGRectMake((self.frame.size.width - (widthOfBadge))/2,  
								imageViewSize + 5,  
								widthOfBadge,  
								sizeOfText.height);  

Autoresizing masks sometimes helped, but they weren’t as flexible as their names suggested.

_imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;  

(This is all real code. Instance variables have been changed to protect the innocent.)

As more programs were written, techniques were discovered to abstract away some of the mess. But it was still procedural C, and it was still kinda hard to read.

Then came Auto Layout. Auto Layout is slow, confusing, and verbose. But it’s declarative, and it solves a system of equations every time it lays out your code, which is just plain cool.

These are all layout abstractions, but none of them are great. What do we want out of a great layout abstraction?

  1. We want it to be code. Interface Builder is an impressive tool that gets more impressive with every release. But it’s fundamentally not as expressive as code, doesn’t play well with source control, and generates components that aren’t reusable (we can’t conditionally apply a layout to a view, for example).
  2. We want it to be fast. We’re dealing with primitive numbers here. There’s no reason calculations should take a long time.
  3. We want it to be simple. You should be able to glance at it and tell what the layout looks like. The code should be concise and straightforward.
  4. We want it to be expressive. You should be able to describe any layout with the abstraction.
  5. The abstraction should be very malleable. Easy things should be easy, and hard things should be possible.

Since no layout abstraction can satisfy all of these criteria, we’re making a trade-off with any solution that we pick. Auto Layout trades speed and simplicity for the ability to be expressed in Interface Builder. Anyone who’s tried to set up constraints in code knows how painful using even the visual format language can be. Libraries like CompactConstraint or Cartography can help with the verbosity of Auto Layout, but the point I want to press here is that Auto Layout isn’t the ultimate form of expressing layouts.

Even though Apple engineers have been subtly and not-so-subtly pushing us towards Auto Layout since it was released, and maybe one day we won’t be allowed to use anything but Auto Layout, computers are Turing-complete. You don’t have to wait for anyone: write your own future.

For me, the most natural way to think about it is that views should have a layout, the same way they have subviews. You could hot-swap this layout for lots of reasons: to perform an animation, present the same views on different devices, or A/B test different layouts. If your view is HTML markup, your layout object would be the CSS.

Maybe you like the rectangle-slicing CGRectDivide model of layout. What would that look like if it were an object, instead of a procedure? Can it be more than just C functions that are called sequentially? Does our  RectDivider object have access to the class of its target view? Can it use names instead when applying rects to subviews, to reduce coupling?

Or maybe you like Java’s configurable Layout Managers. Layout Managers let you pick a strategy, like “fill”, or “stack”, or “grid”, and pass in a list of views which will have that layout strategy applied to them. Here’s an exploration of them in iOS, and here’s a library that approaches layout managers in a slightly different way.

Or maybe you like CSS’s flexbox. Flexbox is a new CSS display style that not all browsers have implemented yet. It lays out views in a row (either horizontal or vertical) and lets you assign which subviews have fixed width (or height), and which subviews should be stretched out to fill the view. You can imagine how powerful this can be when coupled with a scroll view.

What do I want? Sometimes I just want to write an object and have the layout engine just figure out what to do:

@implementation SKUserCellLayoutSpecification

- (CGFloat)imageViewDimension {  
	return self.height;  
}

- (CGSize)sizeForImageView {  
	return CGSizeMake(self.imageViewDimension, self.imageViewDimension);  
}

- (CGPoint)originForLabel {  
	return CGPointMake(0, self.imageViewDimension);  
}

- (CGFloat)widthForLabel {  
	return self.width - self.imageViewDimension;  
}

- (CGFloat)heightForLabel {  
	return self.height;  
}

@end  

Maybe something this abstract could finally prevent us from having to write our layout code twice: once in -sizeThatFits: and once in -layoutSubviews.

But most of the time I just want to pick between them all. I want a protocol that every layout conforms to, and I want to be able to swap between them at will. Maybe some of the concrete implementations are backed with Auto Layout, and others with a layout manager. You’d finally be able to pick the right tool for the job. And that seems like a future worth writing.

Further exploration

There are a few places where I drew inspiration for this post, in order of age:

  • Colin T.A. Gray, who worked on MotionKit, a part of RubyMotion, uses Layout objects to push everything down from the view controller, not just for positioning views. Nevertheless, his library provides a cool (Ruby) DSL for adding constraints and fetching frames. He gave a talk on MotionKit in 2014, which you can find here (direct link to 13:47).
  • Facebook’s Paper uses two abstractions, Metrics and LayoutSpec. You can see more in their tech talk, Building Paper (direct link to 20:55). This is a pretty cool structure, and they separate calculation of their rects from their application, solving the -sizeThatFits: / -layoutSubviews problem. Their LayoutSpecs can also be defined in JSON, meaning their designers can write them and check them in, with no help from engineers.
  • Facebook’s React Native has a reimplementation of Flexbox for use in their Javascript app engine. You can find out more in the React Native Keynote (direct link to 13:07). While it’s probably designed for use only in their JS framework, it would be awesome if we could even apply it to arbitrary UIViews.
  • Josh Abernathy’s SwiftBox is an implementation of FlexBox for Swift.