(Static) UITableView and Dynamic Type

With iOS7 Apple introduced Dynamic Type, which allows the user of an iOS device to adjust the preferred text size in the accessibility settings. This will also affect the text size in any app that adopts Dynamic Type.

In practice I’ve been struggling a little bit to get my UITableViews to respond correctly to a change in the text size. Especially a static TableView requires some specific settings to behave the way it should.

Dynamic UITableView

Let’s first talk about a ‘regular’ TableView that uses one or more prototype cells. Here, things are quite easy. Using the default basic UITableViewCell, you’ll get the correct behavior almost for free.¬†However, using the basic settings only makes the text grow or shrink in case the user changes the text size. The height of the UITableView cell doesn’t adjust to the new text size:

UITableView doesn't resize

To achieve the correct self-sizing of the cell, we will need a little bit of extra code:

This will make the cells grow to accommodate the larger text size. We’re done!

UITableView correct behavior

Static UITableView

Things are more complicated for static tableViews. Just setting the cell style to ‘Basic’ or ‘Right Detail’ will (in Xcode 7 and Xcode 8 beta 6) lead to the disappearance of the textLabels when changing the text¬†size.

To overcome this problem we must set the table view cell style to ‘Custom’ and drag a label (or labels) in ourselves. We then use auto layout to constrain the labels to the Content View of the cell like this:

UITableViewCell constraints

We also need an outlet for all of the labels we just put in our tableView. Because we don’t need an outlet to each specific label, this is a great use case for an IBOutletCollection. Control drag from an arbitrary label to your viewController code and select ‘Outlet Collection’ in the dialog. You can now connect every label that you want to self-resize to this outlet collection:

IBOutletCollection

Finally, we don’t specify a specific font size for the label text, but we use the ‘Body’ text style instead:

UITableViewCell_body_text

The app will now adjust the text size to the preferences given in the accessibility settings. However, there are still two problems:

– The row height of the cell isn’t adjusted to make room for a larger text size.
– The text size isn’t adjusted immediately after the setting is changed.

To fix the first problem we can use almost the same code that we used in the dynamic TableView. For some unclear reason, just setting the rowHeight property on the tableView to UITableViewAutomaticDimension isn’t enough in a static UITableView. We need to implement and override the ‘heightForRowAtIndexPath’ method, which is called for every cell while loading the tableView:

We return UITableViewAutomaticDimension here. The size of the cell will now auto adjust to a change in text size.

To fix the second problem, we need to respond somehow to a change in the content size settings. A new property called ‘adjustsFontsForContentSizeCategory’ that was introduced in iOS 10 makes this easy for us. Setting this property to true causes the font to update automatically when the user changes the text size:

For iOS 9 and lower, we need to listen to a notification that the system posts when the user changes the text size. For that, we have to add an observer for this notification in viewDidLoad.

We also have to implement the method that will be called when the notification is received:

As you can see, we explicitly set the font property of all of our labels to the ‘Body’ style, just like we did in our Storyboard. This will do the trick: the labels now immediately respond when the user selects a different text size.

If you want the text of your labels to use multiple lines in case of a large font size, don’t forget to set the number of lines to zero like this:

UITableViewCell_zeroLines

For demonstration purposes I’ve created a simple sample project.

  • Grigory Entin

    Thanks for the article! I’ve just tried it on iOS 11 at it looks like the solution for dynamic table views works there for static table views as well.