Skip to content

Instantly share code, notes, and snippets.

@loganmoseley
Forked from khanlou/ScalableFonts.swift
Last active February 1, 2022 04:24
Show Gist options
  • Save loganmoseley/38197bd8556ba3578a336f7d9144a933 to your computer and use it in GitHub Desktop.
Save loganmoseley/38197bd8556ba3578a336f7d9144a933 to your computer and use it in GitHub Desktop.
import SwiftUI
import UIKit
enum ScalableFont {
case system(size: CGFloat, weight: Font.Weight = .regular, design: Font.Design = .default)
case custom(_ name: String, size: CGFloat)
var size: CGFloat {
switch self {
case let .system(size: size, weight: _, design: _):
return size
case let .custom(_, size: size):
return size
}
}
func makeFont(withScaledSize scaledSize: CGFloat) -> Font {
switch self {
case let .system(size: _, weight: weight, design: design):
return .system(size: scaledSize, weight: weight, design: design)
case let .custom(name, size: _):
return .custom(name, size: scaledSize)
}
}
}
struct ScaledFontModifier: ViewModifier {
@Environment(\.sizeCategory) var sizeCategory
var scalableFont: ScalableFont
func body(content: Content) -> some View {
let sizedTraits = UITraitCollection(preferredContentSizeCategory: sizeCategory.asUIContentSizeCategory)
let scaledSize = UIFontMetrics.default.scaledValue(for: scalableFont.size, compatibleWith: sizedTraits)
return content.font(scalableFont.makeFont(withScaledSize: scaledSize))
}
}
extension View {
func scalableFont(_ scalableFont: ScalableFont) -> some View {
return self.modifier(ScaledFontModifier(scalableFont: scalableFont))
}
}
extension ContentSizeCategory {
var asUIContentSizeCategory: UIContentSizeCategory {
switch self {
case .extraSmall: return .extraSmall
case .small: return .small
case .medium: return .medium
case .large: return .large
case .extraLarge: return .extraLarge
case .extraExtraLarge: return .extraExtraLarge
case .extraExtraExtraLarge: return .extraExtraExtraLarge
case .accessibilityMedium: return .accessibilityMedium
case .accessibilityLarge: return .accessibilityLarge
case .accessibilityExtraLarge: return .accessibilityExtraLarge
case .accessibilityExtraExtraLarge: return .accessibilityExtraExtraLarge
case .accessibilityExtraExtraExtraLarge: return .accessibilityExtraExtraExtraLarge
@unknown default: return .large // The default Dynamic Type size.
}
}
}
@loganmoseley
Copy link
Author

Forked from Soroush’s to play nicely in SwiftUI Previews, where UIFontMetrics cannot see SwiftUI-environment overrides. Instead of letting UIFontMetrics read the ambient UIContentSizeCategory, we make it calculate based on the SwiftUI value.

Upshot: You can make a group of previews that show your UI at different font sizes, which will work in a running app!

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