Article summary
As I age, my ability to see small text on my iPhone gets worse. The Dynamic Type feature allows iPhone users to make the text larger on their iPhones. In this blog post, I will show you how to get Dynamic Type to work with a static UITableView
.
The Problem
I discovered an issue with Dynamic Type the other day. Any screens in my app that used a static UITableView
were not resizing to account for the larger label size inside the cells. Instead, the cells would be blank. The problem occurred when the user changed the Dynamic Type setting while my app was still running. (If the app was not running at the time, it would work properly.)
Even though the cell height was set to be automatic on the table view, I was still seeing a problem–clearly a bug with Apple’s UITableView
.
However, the screens that used a dynamic UITableView
had no issue. The cells would resize properly to accommodate the larger text.
How to Enable Dynamic Type
To change the Dynamic Type setting on your phone or simulator, go to Settings > General > Accessibility > Larger Text. There, you will see a switch to enable larger accessibility sizes. You do not need to turn this on, but if you do enable it, even larger text sizes will be available to you. Where you want to make the change is at the bottom of the page, where there’s a slider to set the size of the text.
It is easy to support this setting in your app. Wherever you have a label in your app, make sure you change these two settings. First, set the text style to one of the preferred text styles provided by Apple.
Next, set your UILabel
to automatically adjust the font size to type changes.
If your label is in a UITableViewCell
, make sure you have the height of all cells set to automatic on the UITableView
.
The Fix for Static UITableViews
When a user changes the Dynamic Type, the system sends a UIContentSizeCategoryDidChange
event that your app can listen to respond to the change. If you have the Dynamic Type setting turned on in your label, the UITableView
internally adds an observer for this event and adjusts the cell heights accordingly.
This works for dynamic table views, but something is broken for static table views. The first step in fixing the problem is to remove the observer from the UITableView
, so it doesn’t do whatever it is doing to make the text in the cells blank. The second step is to add our own observer to the event, so we can fix the problem ourselves.
func fixDynamicTypeForStaticTableViews() {
// Remove the observer from the table view to prevent it from blanking out the cells
NotificationCenter.default.removeObserver(tableView, name: .UIContentSizeCategoryDidChange, object: nil)
// Add our own observer and handle it ourselves
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeChanged), name: .UIContentSizeCategoryDidChange, object: nil)
}
Call the fixDynamicTypeForStaticTableViews
in your viewDidLoad
function. Now that we have removed the observer from the table view and added our own, we need to implement the contentSizeChanged
function that will get called when the event is fired.
All we need to do in this function is tell the table view to reload itself. The cells will get resized appropriately, and the text inside the cells will respond to the Dynamic Type setting. Notice that I have the @objc attribute on the function that indicates this code will be called from Objective-C.
@objc func contentSizeChanged() {
tableView.reloadData()
}
That is all that we need to do to fix static UITableViews
. Let me know if this fix helped you out.
I was banging my head against this issue, and your article saved me. Thank you!
Better solution just add delegate
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}