Readable Content Guides

If you can target iOS 9 Layout Anchors and Layout Guides make Auto Layout a lot easier. In this post I want to cover a special type of layout guide - the readable content guide. If you have text that stretches across the width of the device you can get lines that are so long they become hard to read. This is especially true on larger devices like the iPad. The readable content guide creates an area that can be easily read without you losing track of the lines.

Interface Builder

It is possible to create constraints using the readable content guide in Interface Builder but the feature is well hidden. In this example I have a single UILabel with leading and trailing constraints to the margins of the root view. A third constraint fixes the label to the bottom of the top layout guide.

Lorum Text Label

The label has the number of lines set to zero (unlimited) and is using the body dynamic text style. At this point we have nothing unusual, here are the three constraints in Interface Builder:

Standard constraints

The problem comes when we read this text on a wide device. This is how this view looks on an iPad Air 2 in landscape orientation (at 50% scale):

Layout Margins

The leading and trailing margins in this case are just 20 points making the label 984 points wide. The line length exceeds 130 characters and is not much fun to read.

The solution is to constrain the text label to the readable content guide of the root view instead of the layout margins. In Interface Builder click on the root view and using the size inspector choose Follow Readable Width:

Follow Readable Width

Not the easiest to find but now we have a much more readable line length. I have added some size guides to make it easier to see what is happening:

Readable width

The readable content guide defines an area that is 672 points wide and inset 176 points from the edges of the view. The line length is now a much more readable 87 characters. As a general recommendation, constrain single columns of text to the readable content guide of their superview and not the layout margin.

The system tries to maintain the line length to a readable size as the view width changes. Rotating the device to portrait keeps the content size the same, albeit with smaller margins.

Portrait

Note that the readable content guide will never extend beyond the view’s layout margin guide.

Dynamic Type

The interesting thing about the readable content guides is that they adapt not only to the changing size of the view but also to dynamic type size. This should not be a surprise if you remember that the idea is to keep the character count of the lines to a readable size.

So if I choose the smallest dynamic type size the content guide width decreases to maintain the line length. The text label shrinks from 672 points to 560 points:

Smallest dynamic type size

Choosing the largest of the standard dynamic type sizes has the reverse effect. The content guide width grows to 896 points to maintain a readable line length:

largest dynamic type size

Creating Constraints in Code

The readableContentGuide is a property on UIView of type UILayoutGuide like layoutMarginsGuide. It has the usual layout anchors we can use to create constraints. So if we have a UILabel created in code

var textLabel = UILabel()

and configured from the viewDidLoad method of the view controller:

textLabel.text = "Lorem ipsum..."
textLabel.numberOfLines = 0
view.addSubview(textLabel)

Remember to disable the automatic translation of the autoresizing mask and then fix the label to the bottom of the top layout guide:

textLabel.translatesAutoresizingMaskIntoConstraints = false
textLabel.topAnchor.constraintEqualToAnchor(topLayoutGuide.bottomAnchor).active = true

Now to make this label fit within the readable content guides of the view we create leading and trailing constraints between the text label and the layout anchors of the readableContentGuide property of the view:

let guide = view.readableContentGuide
guide.leadingAnchor.constraintEqualToAnchor(textLabel.leadingAnchor).active = true
guide.trailingAnchor.constraintEqualToAnchor(textLabel.trailingAnchor).active = true

Note that this is almost identical to creating constraints to the layout margins. The only difference is that we use readableContentGuide instead of layoutMarginsGuide.

// let guide = view.layoutMarginsGuide

Further Reading