Skip to content

Instantly share code, notes, and snippets.

@zats
Last active October 22, 2023 22:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zats/ffb33ec7a50fd3d03e3af20631de2151 to your computer and use it in GitHub Desktop.
Save zats/ffb33ec7a50fd3d03e3af20631de2151 to your computer and use it in GitHub Desktop.
Scaling values proportional to font in SwiftUI

Context

In UIKit we have access to a bunch of useful methods on UIFont such as UIFontMetrics.scaledValue(…) it allows to convert value to proportional one when user adjusts the dynamic size settings This is currently not support in SwiftUI, following extensions should help

TL;DR this method only works for system text styles which is more than I need for my app

public extension UIFont {
    convenience init(_ font: Font) {
        guard let textStyle = font.uiTextStyle else {
            fatalError("Unsupported font")
        }
        let metric = UIFontMetrics(forTextStyle: textStyle)
        let size = metric.scaledValue(for: UIFont.systemFontSize)
        let descriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .caption1)
        self.init(descriptor: descriptor, size: size)
    }
}

public extension Font {
    var uiTextStyle: UIFont.TextStyle? {
        switch self {
        case .body:
            return .body
        case .callout:
            return .callout
        case .caption:
            return .caption1
        case .caption2:
            return .caption2
        case .footnote:
            return .footnote
        case .headline:
            return .headline
        case .largeTitle:
            return .largeTitle
        case .subheadline:
            return .subheadline
        case .title:
            return .title1
        case .title2:
            return .title2
        case .title3:
            return .title3
        default:
            return nil
        }
    }

    func scaledValue(_ value: CGFloat) -> CGFloat {
        guard let uiTextStyle else { return value }
        let metric = UIFontMetrics(forTextStyle: uiTextStyle)
        let result = metric.scaledValue(for: value)
        print(value, result)
        return result
    }
}

Shortcomings

Currently I found no way to get the current fontSize from the Font value, as such this method only works with system styles

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment