I have a method for creating an auto-scaling font based on Dynamic Type that looks like so:
extension UIFont {
public static func getAutoScalingFont(_ fontName: String, _ textStyle: UIFont.TextStyle) -> UIFont {
// getFontSize pulls from a map of UIFont.TextStyle and UIFont.Weight to determine the appropriate point size
let size = getFontSize(forTextStyle: textStyle)
guard let font = UIFont(name: fontName.rawValue, size: size) else {
return UIFont.systemFont(ofSize: size)
}
let fontMetrics = UIFontMetrics(forTextStyle: textStyle)
let traitCollection = UITraitCollection(preferredContentSizeCategory: UIApplication.shared.preferredContentSizeCategory)
let fontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: textStyle, compatibleWith: traitCollection)
return fontMetrics.scaledFont(for: font, maximumPointSize: fontDescriptor.pointSize)
}
}
This seems to work great; when I change the Text Size slider value in the phone Settings, the font scales as necessary.
I'm now trying to add the logic for a minimum UIContentSizeCategory. That is, if the user sets their Text Size value to be less than my specified minimum size category, the font should scale as if they've selected the minimum value.
Here's my attempt:
extension UIFont {
// This variable represents the minimum size category I want to support; that is, if the user
// chooses a size category smaller than .large, fonts should be scaled to the .large size
private static let minimumSupportedContentSize: UIContentSizeCategory = .large
public static func getAutoScalingFont(_ fontName: String, _ textStyle: UIFont.TextStyle) -> UIFont {
let size = getFontSize(forTextStyle: textStyle)
guard let font = UIFont(name: fontName.rawValue, size: size) else {
return UIFont.systemFont(ofSize: size)
}
// I've extended UIContentSizeCategory to adhere to Comparable so this works fine
let contentSize = max(UIApplication.shared.preferredContentSizeCategory, minimumSupportedContentSize)
let fontMetrics = UIFontMetrics(forTextStyle: textStyle)
let traitCollection = UITraitCollection(preferredContentSizeCategory: contentSize)
let fontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: textStyle, compatibleWith: traitCollection)
return fontMetrics.scaledFont(for: font, maximumPointSize: fontDescriptor.pointSize)
}
}
Via logs I'm able to tell that, as expected, the contentSize
I pass into the UITraitCollection initializer is never a value smaller than .large
. However, it seems like the value passed to that initializer represents a maximum content size category. That is, if I init the trait collection like so:
let traitCollection = UITraitCollection(preferredContentSizeCategory: .large)
the font will re-scale for all UIContentSizeCategory's smaller than .large
but will not re-scale for any categories larger than .large
.
Does anyone know how to accomplish setting a minimum UIContentSizeCategory?