Exploring Freelancing
Navigate freelancing as a developer; find clients, manage contracts, ensure timely payment, and learn from experiences!
While working on the next update for Quoting, I realized that the fonts are all over the place, and inconsistencies are creeping in. Someplace it is title3
with light weight, someplace it is title2
with regular weight.
I created a folder for Design System to overcome this problem and have consistency across the app for a smoother future update cycle. This is the part of the series that talks about the fonts.
I took inspiration from Building a SwiftUI Design System – Part 2: Colors, Typography, Iconography, Animation written by Joel Pöllänen and modified the idea according to my needs.
To start, the app uses a custom font Nunito. I play around with fonts once in a while, like Montserrat or Poppins, and changing it at one place is so convenient.
Font Type
The enum FontType
contains the cases for the font types and has a variable to return the capitalized name.
enum FontType: String {
case montserrat
case josefinSans
case poppins
case openSans
case sourceSansPro
case nunito
var name: String {
self.rawValue.capitalized
}
}
Font Weight
Then, there’s another enum, FontWeight
, to define the various weights that are commonly used. It follows the convention of naming it by appending a “-“ in front of the capitalized name:
enum FontWeight: String {
case extraLight
case light
case thin
case regular
case medium
case semiBold
case bold
case extraBold
case black
case extraLightItalic
case lightItalic
case thinItalic
case regularItalic
case mediumItalic
case semiBoldItalic
case boldItalic
case extraBoldItalic
case blackItalic
var name: String {
"-" + self.rawValue.capitalized
}
}
Note that this enum has all the possible cases and doesn’t check if there’s any missing font.
Custom Font Methods
For the custom font method, I created an extension on Font
and added two variations of static private methods:
font(type:weight:style:)
font(type:weight:size:)
They’re private so that I don’t accidentally use them anywhere. From iOS 14 and above, the custom font sizes automatically update with the system sizes, so this implementation works great to support Dynamic Type:
@available(iOS 14, *)
extension Font {
/// Use this method for custom fonts with variable weight and style.
/// Dynamically updates the font size with the system size.
/// - Parameters:
/// - type: Cases that describe the preferred type of font.
/// - weight: Cases that describe the preferred weight for fonts.
/// - style: Constants that describe the preferred styles for fonts.
/// - Returns: Custom font based on the parameters you specified.
static private func font(type: FontType, weight: FontWeight, style: UIFont.TextStyle) -> Font {
.custom(type.name + weight.name, size: UIFont.preferredFont(forTextStyle: style).pointSize)
}
/// Use this method for custom fonts with variable weight and size.
/// Dynamically updates the font size with the system size.
/// - Parameters:
/// - type: Cases that describe the preferred type of font.
/// - weight: Cases that describe the preferred weight for fonts.
/// - size: Constants that describe the preferred size for fonts.
/// - Returns: Custom font based on the parameters you specified.
static private func font(type: FontType, weight: FontWeight, size: CGFloat) -> Font {
.custom(type.name + weight.name, size: size)
}
}
Combining the type and weight name becomes similar to the font’s file name referenced in the Info.plist
. For example, Nunito-SemiBoldItalic.ttf.
Now that the base is ready, it’s time to create the custom fonts!
Custom Fonts Naming
If I use the same name as SwiftUI’s font like headline
or body
, it works well, but SwiftUI previews can’t distinguish between the two and won’t run at all. To solve that problem, I prepended the constants with the word “app”:
@available(iOS 14, *)
extension Font {
/// A font with the large title text style.
static let appLargeTitle = font(type: .nunito, weight: .bold, style: .largeTitle)
/// A font with the title text style.
static let appTitle = font(type: .nunito, weight: .bold, style: .title1)
/// A font for second level hierarchical headings.
static let appSecondaryTitle = font(type: .nunito, weight: .bold, style: .title2)
/// A font for third level hierarchical headings.
static let appTertiaryTitle = font(type: .nunito, weight: .bold, style: .title3)
/// A font with the headline text style.
static let appHeadline = font(type: .nunito, weight: .bold, style: .headline)
/// A font with the body text style.
static let appBody = font(type: .nunito, weight: .regular, style: .body)
/// A font with the callout text style.
static let appCallout = font(type: .nunito, weight: .regular, style: .callout)
/// A font with the caption text style.
static let appCaption = font(type: .nunito, weight: .regular, style: .caption1)
/// A font with the credits text style.
static let appCredits = font(type: .nunito, weight: .light, style: .caption2)
}
The above list is all the fonts used in Quoting app. If I plan to change the title to be extra bold of type Poppins, it’ll just be a single line of change!
Usage
Using it is as simple as using SwiftUI’s default fonts. You use the font
modifier:
struct TitleView: View {
private var title: String
init(_ title: String) {
self.title = title
}
var body: some View {
Text(title)
.font(.appLargeTitle)
.frame(maxWidth: .infinity)
.padding(.leading)
}
}
Conclusion
Having a typography system from the beginning or while refactoring helps you sort the fonts in one place, which becomes the source of truth. It creates consistency across the app and gives you the ease of updating any font in a single file.
The second part of this series will be about creating a Color System.
If you have a better approach, please tag @rudrankriyam on Twitter! I love constructive feedback and appreciate constructive criticism.
Thanks for reading, and I hope you’re enjoying it!
Exploring Freelancing
Navigate freelancing as a developer; find clients, manage contracts, ensure timely payment, and learn from experiences!