Since iOS 15 you can set limits on the minimum and maximum sizes of dynamic type. It works for both UIKit and SwiftUI.
// UIKit view.minimumContentSizeCategory = .medium view.maximumContentSizeCategory = .accessibilityExtraLarge // SwiftUI ContentView() .dynamicTypeSize(.medium ... .accessibility3)
Minimum and Maximum Content Size
In iOS 15 Apple added two properties to
UIView that let you limit the minimum and maximum content size of dynamic type:
var minimumContentSizeCategory: UIContentSizeCategory? var maximumContentSizeCategory: UIContentSizeCategory?
When you set one or both of these properties on a view it limits the dynamic type size for that view and any of its subviews. Setting the property to
nil removes the limit. If you set an invalid range, so that the minimum is greater than the maximum, only the maximum value applies.
For example, to limit the dynamic type size in a view hierarchy to the range
view.minimumContentSizeCategory = .medium view.maximumContentSizeCategory = .accessibilityExtraLarge
Since these are properties of
UIView they are also available on subclasses like
UITextView. This gives you fine grained control to limit an individual text element without affecting other text:
pubLabel.minimumContentSizeCategory = .large
For debugging purposes, there’s a property on
UIView that gives you a description of the content size a view is using together with any limits applied to it or inherited from a superview:
For example, with my preferred content size set to accessibility-medium (AX-M), and an upper limit on a label set to XXXL, the label is limited to XXXL:
3. <UIView:0x155f175f0>: - <= (none->)AX-M <= XXXL 2. <UIStackView:0x155f11c00>: - <= (AX-M->)AX-M <= XXXL 1. <UILabel:0x155f112e0>: - <= (AX-M->)XXXL <= XXXL --> XXXL
Adding an upper limit on the root view to XL results in limiting the label to XL:
3. <UIView:0x14ad145c0>: - <= (none->)XL <= XXXL 2. <UIStackView:0x14ad0e170>: - <= (XL->)XL <= XXXL 1. <UILabel:0x14ad27680>: - <= (XL->)XL <= XXXL --> XL
SwiftUI Dynamic Type Ranges
For SwiftUI, you apply a dynamic type size range as a modifier to a view. For example, to limit text to be no bigger than
// Limit text to no bigger than accessibility1 Text("Hello, world!") .font(.title) .dynamicTypeSize(...DynamicTypeSize.accessibility1)
If you want to set a lower limit:
// No smaller than .large .dynamicTypeSize(.large...)
Or to keep the text within a range:
// No smaller than large, no bigger than accessibility1 .dynamicTypeSize(.large ... .accessibility1)
If you set multiple ranges the result is their intersection. If you forget the range and set a single value the text appears at that size. Probably not what you want other than as a quick way to preview text at a certain size:
Don’t Limit Readability
My fear when I saw this feature was that it might tempt developers to use it instead of creating layouts that work at the largest accessibility text sizes. Here’s a quote from the Apple engineer in the WWDC session:
Please do not use this API to unduly limit text size. These settings serve an extremely important function, and it’s paramount that your app’s functionality is all available, and everything is legible, to people using the highest text size setting.
In other words, it might be ok to limit the size of a title or headline that is already large. Don’t use this as a way of fixing problems with your layout.
See the following WWDC sessions:
If you want to learn more about building adaptive layouts with dynamic type you might like my book - Modern Auto Layout.