Dynamic type is an essential iOS feature that allows the user to choose their preferred text size. Find out what it means and how you can support it in your App.
Last updated: Nov 10, 2022
Dynamic Type
Apple first introduced dynamic type way back in iOS 7. It provides the user with the ability to specify their preferred text size in the Display & Brightness settings of the device. Five extra large text sizes are also available from the Accessibility settings.
When you add support for dynamic type to your applications the user expects you to adjust your text for their preferred reading size:
Text Styles
Apple introduced the UIFontDescriptor
class with iOS 7 to provide a way to describe the attributes of a font such as the font family, size and whole set of other attributes. This makes it easier to create new UIFont
objects based on a common set of attributes. One of the attributes introduced with iOS 7 was the text style.
A text style is a pre-defined constant that provides a short hand way of creating a UIFontDescriptor
or by extension a UIFont
with a predetermined set of attributes. There were six text styles introduced with iOS 7:
.headline .subheadline .body
.footnote .caption1 .caption2
In iOS 9, Apple added four more styles:
.title1 .title2 .title3
.callout
In iOS 11, Apple added the large title style:
.largeTitle
The UIFont
class includes a class method that returns an instance of the font with the given text style. For example, to create a font suitable for use as a headline:
// Swift
let myFont = UIFont.preferredFont(forTextStyle: .headline)
If you’re using Objective-C the syntax is a little more verbose:
// Objective-C
UIFont *myFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
The important point to understand with these preferred fonts is that Apple decides the details for the font including the user’s preferred text size. The screenshots below show how the font for each text style changes for the extra-small, default extra-large and the extra-extra-extra-large setting of the text size:
In iOS 7 Apple used the Helvetica Neue font family for the preferred font. That changed to Apple’s own San Francisco font in iOS 9. In both cases, Apple takes care of sizing, spacing and other attributes to make the text legible for all text styles and sizes.
Text Styles In Interface Builder
There is full support for text styles in Interface Builder when creating UIKit controls. For example, for a UILabel
object the font setting in the attributes inspector allows you to directly set the text style used for the label:
Implementing Support For Dynamic Type
To show how to support Dynamic Type I have created an example app that has a stack view containing a UILabel
for each of the possible text styles (excluding the large title which needs at least iOS 11). The view controller as it appears in Interface Builder is shown below.
Each text label has the corresponding text style directly set in Interface Builder:
If you’re minimum deployment target is at least iOS 10, make sure to set the “Automatically Adjusts Font” checkbox. The system will then automatically update the font size anytime the user changes their preferred text size.
Since the size of each of the text labels can vary at runtime we need an adaptive layout. In this case I’ve embedded my stack view in a scroll view to allow the stack view to extend beyond the height of the device. Take a look at Scroll View Layouts With Interface Builder for a detailed walk through of this type of layout.
Note: It is not mandatory to use Auto Layout with preferred fonts but it does make life a whole lot easier. With dynamic type and preferred fonts the size of a text field can change anytime the user changes the text size setting. Managing this yourself is likely to be a frustrating experience.
If You Need To Support iOS 9
To support dynamic type with iOS 9, or earlier, you need to update the preferred font of your text any time the user changes the size. You can do that by listening for the content size category did change notification and manually updating the font of any labels, text fields and text views.
To avoid build warnings you’ll need to uncheck the “Automatically Adjusts Font” setting in Interface Builder:
We can check the availability of the setting in the viewDidLoad
method of the view controller. If we are running iOS 10 or later we can set the property in code for each of the labels. Otherwise we create an observer for the notification:
// Swift
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 10, *) {
allLabels.forEach {
$0.adjustsFontForContentSizeCategory = true
}
} else {
NotificationCenter.default.addObserver(self,
selector: #selector(updateTextStyles(_:)),
name: UIContentSizeCategory.didChangeNotification,
object: nil)
}
}
// Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
if (@available(iOS 10, *)) {
for (UILabel *label in self.allLabels) {
label.adjustsFontForContentSizeCategory = YES;
}
} else {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(updateTextStyles:)
name:UIContentSizeCategoryDidChangeNotification
object:nil];
}
}
Then in the method that handles the notification we update the font of each of the labels:
// Swift
@objc private func updateTextStyles(_ notification: Notification) {
title1Label.font = UIFont.preferredFont(forTextStyle: .title1)
title2Label.font = UIFont.preferredFont(forTextStyle: .title2)
title3Label.font = UIFont.preferredFont(forTextStyle: .title3)
...
}
// Objective-C
- (void)updateTextStyles:(NSNotification *)notification {
self.title1Label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleTitle1];
self.title2Label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleTitle2];
self.title3Label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleTitle3];
...
}
The lack of auto-adjusting font sizes makes supporting dynamic type on iOS 9 and earlier a bit of a pain.
What About Other Fonts?
If you want to use your own custom fonts with dynamic type take a look at this post (requires at least iOS 11):
Get The Code
You can find the example Dynamic Text Xcode project in my GitHub CodeExamples repository.
Get The Book
If you want learn more about using dynamic type to build adaptive layouts take a look at my book Modern Auto Layout.