Preamble:
In application development, fonts play an important role in interface design. Selecting fonts suitable for UI interface will help our application more eye-catching and more convenient to use.
Problem:
In case your project is assigned to customers for final inspection before being submitted to the Appstore. In the end, your app is ok by the customer, but just make small adjustments to the font or font size to enlarge to 1 size and you are assigned to edit the font. As usual you will have to find each UILabel or UITextField on each StoryBoard in the project. It will be very easy if the number of screens is small but imagine there are dozens of screens, it is difficult to find each label. To solve this task quickly we need a measure to manage the change of font or font size.
Method:
- Step 1:
- Bring the fonts you need into the project. Drag and drop fonts into the project resource.
- Step 2:
- Register your fonts in the Info.plist file under the Fonts provided by application (UIAppFonts) key.
- Step 3:
- Make sure the fonts you add to the project, check the font has been registered or not with the Utility.logAllAvailableFonts () function. (All fonts included in the project will be printed in the debug console).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class Utility { /// Logs all available fonts from iOS SDK and installed custom font class func logAllAvailableFonts() { for family in UIFont.familyNames { print("(family)") for name in UIFont.fontNames(forFamilyName: family) { print(" (name)") } } } } // Roboto // Roboto-Thin // Roboto-Italic // Roboto-BlackItalic // Roboto-Light // Roboto-BoldItalic // Roboto-Black // Roboto-LightItalic // Roboto-ThinItalic // Roboto-Bold // Roboto-Regular // Roboto-Medium // Roboto-MediumItalic |
Using:
- Usually we register the font as well as the font size by initializing after UIFont (name: size 🙂 We need to avoid such hard code to easily change the font or font size. We will use 2 enums to do this, one to manage fonts, the other to manage font size.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | enum FontName: String { case RobotoBlack = "Roboto-Black" case RobotoBlackItalic = "Roboto-BlackItalic" case RobotoBold = "Roboto-Bold" case RobotoBoldItalic = "Roboto-BoldItalic" case RobotoItalic = "Roboto-Italic" case RobotoLight = "Roboto_Light" case RobotoLightItalic = "Roboto-LightItalic" case RobotoMedium = "Roboto-Medium" case RobotoMediumItalic = "Roboto-MediumItalic" case RobotoRegular = "Roboto-Regular" case RobotoThin = "Roboto-Thin" case RobotoThinItalic = "Roboto-ThinItalic" } enum StandardSize: Double { case h1 = 20.0 case h2 = 18.0 case h3 = 16.0 case h4 = 14.0 case h5 = 12.0 case h6 = 10.0 } |
- Enum FontName is used to handle all the fonts that we have added to the project. Enum StandardSize is used to handle font sizes in projects.
- In some cases we will need to use the system font or font sizes larger or smaller so we will add 2 Enum to handle that.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | enum FontType { case installed(FontName) case custom(String) case system case systemBold case systemItatic case systemWeighted(weight: Double) case monoSpacedDigit(size: Double, weight: Double) } enum FontSize { case standard(StandardSize) case custom(Double) var value: Double { switch self { case .standard(let size): return size.rawValue case .custom(let customSize): return customSize } } } |
- With the FontType enum, it is easy to use the default font or the font added from the outside. Similarly, Enum FontSize helps you choose the pre-installed typefaces in Enum StandardSize or use custom fonts.
- We will now encapsulate the enum above in the struct Font. This makes it easy to create the font and font size easily.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | struct Font { enum FontType { case installed(FontName) // ... } enum FontSize { case standard(StandardSize) // ... } enum FontName: String { case RobotoBlack = "Roboto-Black" // ... } enum StandardSize: Double { case h1 = 20.0 // ... } // 1 var type: FontType var size: FontSize // 2 init(_ type: FontType, size: FontSize) { self.type = type self.size = size } } |
- We have not yet added any mechanism to initialize UIFont. That will be done via the extension below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | extension Font { var instance: UIFont { var instanceFont: UIFont! switch type { case .custom(let fontName): guard let font = UIFont(name: fontName, size: CGFloat(size.value)) else { fatalError("(fontName) font is not installed, make sure it is added in Info.plist and logged with Utility.logAllAvailableFonts()") } instanceFont = font case .installed(let fontName): guard let font = UIFont(name: fontName.rawValue, size: CGFloat(size.value)) else { fatalError("(fontName.rawValue) font is not installed, make sure it is added in Info.plist and logged with Utility.logAllAvailableFonts()") } instanceFont = font case .system: instanceFont = UIFont.systemFont(ofSize: CGFloat(size.value)) case .systemBold: instanceFont = UIFont.boldSystemFont(ofSize: CGFloat(size.value)) case .systemItatic: instanceFont = UIFont.italicSystemFont(ofSize: CGFloat(size.value)) case .systemWeighted(let weight): instanceFont = UIFont.systemFont(ofSize: CGFloat(size.value), weight: CGFloat(weight)) case .monoSpacedDigit(let size, let weight): instanceFont = UIFont.monospacedDigitSystemFont(ofSize: CGFloat(size), weight: CGFloat(weight)) } return instanceFont } } |
Use:
- initialize UIFont in the usual way:
1 2 3 4 5 6 | let system12 = UIFont.systemFont(ofSize: 12.0) // Hard coded literals -> 1 let robotoThin20 = UIFont(name: "Roboto-Thin", size: 20.0) // Hard coded literals -> 2 let robotoBlack14 = UIFont(name: "Roboto-Black", size: 14.0) // Hard coded literals -> 2 let helveticaLight13 = UIFont(name: "Helvetica-Light", size: 13.0) // Hard coded literals -> 2 |
- And here is how to initialize with the syntax according to the architecture we have implemented above, will look more intuitive and will help us easier to maintainance.
1 2 3 4 5 6 | let system12 = Font(.system, size: .standard(.h5)).instance let robotoThin20 = Font(.installed(.RobotoThin), size: .standard(.h1)).instance let robotoBlack14 = Font(.installed(.RobotoBlack), size: .standard(.h4)).instance let helveticaLight13 = Font(.custom("Helvetica-Light"), size: .custom(13.0)).instance |
- You can find the sample source code above in this link: https://gist.github.com/sauvikatinnofied/3aad89cbafu1908e9b6c7f0e5829c49
- References: https://medium.com/@sauvik_dolui/handling-fonts-in-ios-development-a-simpler-way-32d360cdc1b6