A reading experience guide for iPad app developers

A reading experience guide for iPad app developers

Apr 18, 2016 4 minute read Comments
Auto Layout iOS 9

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 UILabelwith 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.

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:

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):

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 :

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:

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.

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:

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:

view image

Creating Constraints in Code

The readableContentGuideis a property on UIViewof type UILayoutGuidelike 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 viewDidLoadmethod of the view controller:

textLabel.text = "Lorem ipsum..."
textLabel.numberOfLines = 0

First we 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 readableContentGuideproperty 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 create constraints to the layout margins. The only difference is that we use readableContentGuideinstead of layoutMarginsGuide.

//let guide = view.layoutMarginsGuide

Further Reading