Skip to content

Instantly share code, notes, and snippets.

@kevin-hirsch
Created November 19, 2020 12:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevin-hirsch/e5902a3d596e91010b1fe158fce743f4 to your computer and use it in GitHub Desktop.
Save kevin-hirsch/e5902a3d596e91010b1fe158fce743f4 to your computer and use it in GitHub Desktop.
Dynamic Type: Scaling Custom Fonts
# https://github.com/realm/SwiftLint#defining-custom-rules
custom_rules:
use_scaled_fonts:
name: "Use scaled fonts: UIFont.scaledFont(style:)"
regex: '\.(?!scaled)[a-zA-Z]*[fF]ont\('
severity: error
struct TextStyle {
let size: CGFloat
let emphasis: Emphasis
let name: Name
init(size: CGFloat, emphasis: Emphasis = .none, name: Name = .ptSans) {
self.size = size
self.emphasis = emphasis
self.name = name
}
}
extension TextStyle {
typealias Name = String
enum Emphasis {
case none
case bold
case italic
var symbolicTraits: UIFontDescriptor.SymbolicTraits? {
switch self {
case .none:
return nil
case .bold:
return .traitBold
case .italic:
return .traitItalic
}
}
}
}
extension TextStyle.Name {
static let montserrat: TextStyle.Name = "Montserrat-Regular"
static let ptSans: TextStyle.Name = "PTSans-Regular"
}
extension TextStyle {
// MARK: - Headings
static let h1 = TextStyle(size: 24, emphasis: .bold, name: .montserrat)
static let h2 = TextStyle(size: 20, emphasis: .bold, name: .montserrat)
static let h3 = TextStyle(size: 18, emphasis: .bold, name: .montserrat)
static let h4 = TextStyle(size: 16, emphasis: .bold, name: .montserrat)
static let h5 = TextStyle(size: 14, emphasis: .bold, name: .montserrat)
static let h6 = TextStyle(size: 13, emphasis: .bold, name: .montserrat)
// MARK: - Text buttons
static func buttonLarge(emphasis: Emphasis) -> TextStyle {
TextStyle(size: 16, emphasis: emphasis)
}
static func buttonSmall(emphasis: Emphasis) -> TextStyle {
TextStyle(size: 14, emphasis: emphasis)
}
// MARK: - Texts
static let text18 = TextStyle(size: 18)
static let text16 = TextStyle(size: 16)
static let text13 = TextStyle(size: 13)
static let text14 = TextStyle(size: 14)
// MARK: - Text highlights
static let textHighlight24 = TextStyle(size: 24, emphasis: .bold)
static let textHighlight20 = TextStyle(size: 20, emphasis: .bold)
}
protocol TextStyleAdjustable: UIContentSizeCategoryAdjusting {
func setFont(_ font: UIFont)
func apply(textStyle: TextStyle) -> Self
}
extension TextStyleAdjustable {
@discardableResult
func apply(textStyle: TextStyle) -> Self {
setFont(.scaledFont(style: textStyle))
adjustsFontForContentSizeCategory = true
return self
}
}
extension UILabel: TextStyleAdjustable {
func setFont(_ font: UIFont) {
self.font = font
}
}
extension UITextView: TextStyleAdjustable {
func setFont(_ font: UIFont) {
self.font = font
}
}
extension UITextField: TextStyleAdjustable {
func setFont(_ font: UIFont) {
self.font = font
}
}
extension UIButton: TextStyleAdjustable {
func setFont(_ font: UIFont) {
titleLabel?.font = font
}
public var adjustsFontForContentSizeCategory: Bool {
get {
titleLabel?.adjustsFontForContentSizeCategory ?? false
}
set {
titleLabel?.adjustsFontForContentSizeCategory = newValue
}
}
}
extension UIFont {
/// Returns a font matching `style`
static func font(style: <ModuleName>.TextStyle) -> UIFont {
var descriptor = UIFontDescriptor(name: style.name, size: style.size)
if let symbolicTraits = style.emphasis.symbolicTraits {
descriptor = descriptor.withSymbolicTraits(symbolicTraits)!
}
return UIFont(descriptor: descriptor, size: style.size)
}
/// Returns a font matching `style` scaled to the current Content Size Category.
static func scaledFont(style: <ModuleName>.TextStyle) -> UIFont {
UIFontMetrics.default.scaledFont(for: font(style: style))
}
}
label.apply(textStyle: .h1)
textField.apply(textStyle: .text16)
textView.apply(textStyle: .text16)
button.apply(textStyle: .buttonLarge(emphasis: .bold))
// or
label.font = .scaledFont(style: .h1)
label.adjustsFontForContentSizeCategory = true
textField.font = .scaledFont(style: .text16)
textField.adjustsFontForContentSizeCategory = true
textView.font = .scaledFont(style: .text16)
textView.adjustsFontForContentSizeCategory = true
button.titleLabel?.font = .scaledFont(style: .buttonLarge(emphasis: .bold))
button.titleLabel?.adjustsFontForContentSizeCategory = true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment