Skip to content

Instantly share code, notes, and snippets.

@popcornomnom
Last active June 13, 2020 13:19
Show Gist options
  • Save popcornomnom/8806911e081018c893930cbda0c93e49 to your computer and use it in GitHub Desktop.
Save popcornomnom/8806911e081018c893930cbda0c93e49 to your computer and use it in GitHub Desktop.
//
// FontManager.swift
//
// Created by http://www.popcornomnom.com
// Copyright © 2020 Marharyta Lytvynenko. All rights reserved.
//
import UIKit
///optional type in case if you don't want to support scaled font yet
private let autoScaleSettings: AutoScaleSettings? = AutoScaleSettings()
///optional type in case if you want turn off acessability support
private let acessabilitySettings: DynamicTypeSettings? = DynamicTypeSettings()
private class AutoScaleSettings {
let mostPopularScreenWidth: CGFloat = 375
let maxScreenWidth: CGFloat = 460 //use to prevent huge font scaling on iPad
let minScaleFactor: CGFloat = 0.93 //to protect scalling of very small sizes
}
private class DynamicTypeSettings {
let maxPointSizeScaleFactor: CGFloat
init(maxPointSizeScaleFactor: CGFloat = 1.25) {
self.maxPointSizeScaleFactor = maxPointSizeScaleFactor
UILabel.appearance().adjustsFontForContentSizeCategory = true
UITextField.appearance().adjustsFontForContentSizeCategory = true
}
}
//MARK: - Font Parts
public extension UIFont {
enum Family: String, CaseIterable {
case system = ".SFUIText" //".SFUI"
case inter = "Inter"
//easy to change default app fonts family
public static let defaultFamily = Family.inter
}
enum CustomWeight: String, CaseIterable {
case regular = "", medium, light, heavy, bold, semibold, black
}
enum Size: CGFloat, CaseIterable {
case h1 = 36, h2 = 28, h3 = 20
case bodyL = 17, bodyM = 15, bodyS = 13
var doesSupportMinScalling: Bool { return rawValue > Size.bodyM.rawValue } //readability bounds
}
private class func stringName(_ family: Family, _ weight: CustomWeight) -> String {
/**
Define incompatible family, weight here
in this case set defaults compatible values
*/
let fontWeight: String
switch (family, weight) {
case (.inter, .heavy): fontWeight = CustomWeight.bold.rawValue
case (.inter, .light): fontWeight = "\(weight.rawValue)BETA"
default: fontWeight = weight.rawValue
}
//put Family and Weight together
let familyName = family.rawValue
return fontWeight.isEmpty ? "\(familyName)" : "\(familyName)-\(fontWeight)"
}
}
//MARK: - Initializers
public extension UIFont {
convenience init(_ size: Size, _ weight: CustomWeight) {
self.init(.defaultFamily, size, weight)
}
convenience init(_ family: Family = .defaultFamily,
_ size: Size, _ weight: CustomWeight) {
var _size = size.rawValue
if let autoScaleSettings = autoScaleSettings {
var ratio = (min(UIScreen.main.bounds.width, autoScaleSettings.maxScreenWidth)
/ autoScaleSettings.mostPopularScreenWidth)
ratio = max(autoScaleSettings.minScaleFactor, ratio)
if ratio > 1 || (ratio < 1 && size.doesSupportMinScalling) {
_size = round(ratio * _size)
}
}
if let acessabilitySettings = acessabilitySettings {
let originalFont = UIFont(name: UIFont.stringName(family, weight), size: _size)!
let scaledFont = UIFontMetrics.default.scaledFont(for: originalFont,
maximumPointSize: originalFont.pointSize *
acessabilitySettings.maxPointSizeScaleFactor)
self.init(descriptor: scaledFont.fontDescriptor, size: scaledFont.pointSize)
} else {
self.init(name: UIFont.stringName(family, weight), size: _size)!
}
}
}
#if DEBUG
extension UIFont.Size {
var debugDescription: String { "\(self)" }
}
extension UIFont {
class func printAvailableFonts() {
let consoleMessage = UIFont.familyNames.map { UIFont.fontNames(forFamilyName: $0) }
print(consoleMessage)
}
class func printAllFonts() {
let families = UIFont.Family.allCases
let sizes = UIFont.Size.allCases
let weights = UIFont.CustomWeight.allCases
let consoleMessage = families.map { family in
"\(family.rawValue):" + sizes.map { size in
"\n\t\(size.debugDescription):\n\t\t" + weights.map { weight in
"\(UIFont(family, size, weight))"
}.joined(separator: "\n\t\t")
}.joined(separator: "\n")
}.joined(separator: "\n")
print(consoleMessage)
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment