Introduction

For the Rentalcars.com mobile apps, we have two ways to manage icons in the user interface. If the icon has more than one colour or tone, then it will likely be an image, but for any other case, we use an icon font.
That allows for a lighter-weight application as we don’t have to have hundreds of images at three different screen scales (@1x, @2x, @3x) for each one. It is also easier to scale to different sizes and maintain.

Our designers create a custom font and organise each glyph in the online icon tool Fontastic. They can then export it in several formats including TTF (which we import in the apps) and SVG (which is used to generate helpers in order to easily use these icon fonts from code). Whilst this is the case for both iOS and Android, the following blog will dive into how we use and maintain the icon fonts for our iOS app.

Don’t forget to try it for yourself, and admire the beautiful glyphs in our app:
Download Rentalcars for iOS.
Download Rentalcars for Android.

icons1

Font git repo

We have a git repository where designers store the fonts. Here is the project structure for one of our icon fonts:

icons2-1

The html file is really useful to visually see what each icon is named.

Fastlane action

Fastlane is a great set of tools that enables app developers to easily automate tasks such as generating builds, provisioning profiles, code-signing certificates, running tests, deploying builds, etc. We use it as part of our continuous integration set-up, and decided to set up a custom action in Fastlane to generate our font helpers.

An action is just a script written in Ruby. This action first pulls the font’s git repository. It then takes the SVG file for the font and creates the enum and String extension for the font and adds them to the Xcode project.

The SVG file is just an XML format which can be easily accessed from our Ruby script using Nokogiri. What this does is find the font name, and for each glyph extract the name and Unicode value. Our script changes the glyph name a little to remove any characters that we don’t want and set it to lower camel case, which is suitable for Swift enum cases. For instance, an individual glyph named “rc-icons-outlined-air-conditioning” will become “airConditioning” in the enum. The script then exports it in a Swift file that can be added to our Xcode project.

Swift output

The following three pieces of code are not generated – they just live in our project as the foundation of our fonts system.

First we have a protocol that every font class helper must conform to. It contains the font names toString method, and the classic font with size that returns a UIFont.

protocol Icons {
    static var fontName: String {get}
    func toString() -> String
    func font(_ size: CGFloat) -> UIFont
}

Then we have a protocol extension, in order to provide the default implementation of the two functions in the above protocol.

extension Icons where Self: RawRepresentable, Self.RawValue == UInt16 {
    func toString() -> String {
        return "\(UnicodeScalar(UInt16(self.rawValue))!)"
    }

    func font(_ size: CGFloat) -> UIFont {
        return UIFont(name: Self.fontName, size: size)!
    }
}

And here is a helper to easily create an NSAttributedString from the desired icon set, size of glyph, and foreground colour.

extension NSAttributedString {
    convenience init(icon: Icons, size: CGFloat, color: UIColor) {
        self.init(string: icon.toString(), attributes: [NSAttributedStringKey.font: icon.font(size), NSAttributedStringKey.foregroundColor: color])
    }
}

Finally, below is an excerpt of the Swift enum generated with our Fastlane script for one of our icon fonts:

enum IconsOutlined: UInt16, Icons {

    static let fontName = "rc-icons-outlined"

    case androidShare = 61441
    case oldSchoolPhone = 61442
    case aeroplane = 61443
    case aeroplaneRight = 61444
    case airConditioning = 61445
    case bin = 61446
    case bubbleCar = 61447
    (…)
}

Now let’s see how easy it is to use an icon:

iconLabel.attributedText = NSAttributedString(icon: IconsOutlined.airConditioning, size: 16.0, color: UIColor.blue)

Or if you have your label set up in a storyboard/nib or in some other way, then you just need to set the text property:

iconLabel.text = IconsOutlined.airConditioning.toString()

Let us know what you think of icon fonts in the comments below.