How to create UIButtons with FontAwesome icons
iOS 8.3+
Swift 1.2
Font Awesome 4.3.0+
How to create fancy pants buttons
In this tutorial we’ll create UIButtons that display an icon with a text description below. Achieving this is NOT difficult, it’s more tricky than difficult.
You’ll find links to the solutions and other resources at the end of this tutorial.
So that we’re all starting from the same point there is a tutorial starter project over on GitHub. Let’s start by downloading a copy and checking that the project builds — if that’s successful then Hurrah!
Goal
The key functional capabilities we’re aiming for are:
- Customised UIButton — that operates as a normal button
- Font Awesome icons
- Descriptive text below the icon
Reviewing the starter project
We’ll start by taking a look at the starter project. There are some key files and configurations that you need to be aware of.
There are 3 project files and 1 build phase setting to highlight.
- info.plist
- FontAwesome.ttf
- iconfonts-fontawesome.swift
- Project Build Phases — Copy Bundle Resources
In case you’re wondering. I’ve cleaned up and dragged the files we’ll not be needing for this tutorial into the Supporting Files group.
info.plist
You should already be aware that the info.plist “file” is used to specify app specific configurations. Notice that in our starter project the info.plist contains an entry that details the FontAwesome.ttf font. This ONLY tells our app that there is a font called FontAwesome — it DOES NOT ensure the file is included when we build the app.
FontAwesome.ttf
The actual font file. We are using the .TTF version, there is also a .OTF version of the font that you could use if you choose — just ensure the info.plist is accurate. Links to these files are at the end of the tutorial.
iconfonts-fontawesome.swift
This is a support file I have created that provides extensions to UIFont, String and NSMutableAttributedString. The extensions provide the helper methods we’ll use to speed creating interface elements.
It’s worth noting that there are other Swift FontAwesome libraries/support classes to be found GitHub. I chose to create my own because I was never 100% happy with the repositories I found and looked over.
All/Most repositories use large ENUMS or STRUCTS to provide the icon name to unicode conversion and I was concerned with the memory usage of these elements. The Bizzi-Body support file contains a very long switch block, providing the conversion between the full FontAwesome icon name and the Unicode character representation.
UPDATE : 04/05/2015
I was asked by @ashfurrow … “Have you any metrics on memory use of enums?”. Truth is I hadn’t. My opinion was likely formed many years ago using since defunct development languages.
Anyhow — it got me thinking about this and so I ran a couple of tests, switching out the CASE block for an ENUM. Using the Xcode/simulator memory usage metrics I saw that CASE used 16.9mb and the ENUM used 17.0 or 17.1mb. A very un-scientific test I know — that small difference might be explained by the slightly (5! lines) longer source code or the fact that it’s a bank holiday here today or a million and one other things.
@ashfurrow also asked the wider Swift community for their opinion. And the response was that ENUMS should not use more memory. So it really is my aged/legacy/deprecated brain playing tricks on me! ☺
Anyhow. Since I originally wrote the post I also came to realise 2 very good reasons why — for me in this case — I still prefer the CASE version.
1] Duplicate values. There are several alias icons in the FontAwesome catalog and I wanted to use the alias name. Enums don’t allow duplicates of the returned value.
2] Icon names. I was keen to use the icon name as defined by FontAwesome. i.e.: “fa-bank (alias)”. Unfortunately ENUMS don’t allow for special characters like “-” or “(“.
All that said. I would switch to ENUMS if I could because the ENUM code is much cleaner — a lot cleaner, and of course there are no memory issues.
@ashfurrow — Excellent follow up question that got me to think a bit more.
The class extensions provide the following helper methods:
UIFont.iconFontOfSize(font: String, fontSize: CGFloat) -> UIFont {}
This method allows you to specify the font and font size in a single method call.
String.fontAwesomeString(name: String) -> String {}
This method returns the unicode character representation of the target icon as a String.
NSMutableAttributedString.fontAwesomeAttributedString(name: String, suffix: String?, iconSize: CGFloat, suffixSize: CGFloat?) -> NSMutableAttributedString {}
This method returns an AttributedString containing the target icon and any “suffix” text both at their specified target size. This method could easily be extended to provide support for prefix text — consider that your challenge.
Project Build Phases — Copy Bundle Resources
Notice that I have added FontAwesome.ttf to the Copy Bundle Resources section. It is this configuration that ensures the font file is included in the project at build time.
If you skip this setting then it is likely you’ll get optional and/or nil errors.
Storyboard
I’ll only go through adding one button to the storyboard — not the three in the demo shot. I’m sure you’ll be able to create the extra 2 on your own.
Right now we have an empty storyboard. We’ll drag on a UIButton and set some constraints.
Lets wire up the button to the view controller.
Notice that I have wired up an outlet AND an action. The reason for this is that an action is missing the UIButton.titleLabel properties that will hold our icon. So we’ll use the outlet to customise the appearance and the action to manage the interaction.
At this point your view controller should look like this.
Okay. So now we’re at a point where we can customise the button appearance, adding an icon and some descriptive text. For the purpose of this tutorial we’ll keep it simple and plonk all the code in the viewDidLoad() method.
Update your viewDidLoad() method so that it looks like this.
Yuk! Don’t worry — that might look like a lot of code. It’s pretty easy stuff. Let’s step through it.
var buttonString = String.fontAwesomeString(“fa-backward”) + “\nRewind”
This line creates a simple string that contains the unicode representation of the target icon + a new line + “Rewind”. String.fontAwesomeString(“fa-backward”) is one of the helper methods I’ve provided — it converts “fa-backward” to “\u{f04a}”. So the end result of this line is a string that contains “\u{f04a}\nRewind”.
var buttonStringAttributed = NSMutableAttributedString(
string: buttonString,
attributes: [NSFontAttributeName:
UIFont(name: "HelveticaNeue", size: 11.00 )!
]
)
This line creates an NSMutableArttributedString (a string with formatting) version of “\u{f04a}\nRewind” and formats the text using the font Helvetica Neue sized at 11 pts.
A couple of things to note. The text is blue because that is what is defined on the storyboard. Remember the original string contained \n which is an encoded line feed. Now that the string is an attributed string the line feed becomes active.
buttonStringAttributed.addAttribute(
NSFontAttributeName,
value: UIFont.iconFontOfSize("FontAwesome", fontSize: 50),
range: NSRange(location: 0,length: 1)
)
There is a lot happening in this line of code. The gist of it is that we’re adding a “font attribute” to a range of characters within our string.
Let’s break it down.
buttonStringAttributed.addAttribute…
We are adding an attribute to our AttributedString.
NSFontAttributeName, value:…
We are adding the font attribute.
UIFont.iconFontOfSize(“FontAwesome”, fontSize: 50),…
The font is FontAwesome and the size is 50 pt.
range: NSRange(location: 0,length: 1)…
Place this attribute over the string contents from position 0 to position 1.
At this point the attributed string looks like this.
BONUS : If you want something other than blue you have 2 options. You can either adjust the colour in the storyboard, this method will leave both icon and text the same colour. The alternative is to add a colour attribute to the target segment of the attributed string.
buttonStringAttributed.addAttribute(
NSForegroundColorAttributeName,
value: UIColor.blackColor(),
range: NSRange(location: 0,length: 1)
)
Resulting in
The final 3 lines are pretty easy to understand.
button.titleLabel?.textAlignment = .Center
Centre align the output so that the icon and text look connected.
button.titleLabel?.numberOfLines = 2
Ensure the button label has 2 lines of text — otherwise you’ll not see the text below the icon.
button.setAttributedTitle(buttonStringAttributed, forState: .Normal)
Set the button label to use our attributed text. You would need to adjust this line if you have disabled buttons.
Congratulations
That’s all there is to it. Build and run your app. It should look like this.
Links
- FontAwesome
- FontAwesome font file download
- Apple attributed strings programming guide (Mainly Obj’ C — but worth reading/scanning
- GitHub — Tutorial starter project
- GitHub — Tutorial completed project
Where next?
You should not find it too difficult to adjust and repurpose this tutorial code for interface elements beyond the UIButton. How about UILabels?
Remember these tutorials purposly make things simple, I want as many people to get this working and then begin experimenting. Please do not use the “code as is” — spend time with it, refactor it — make it sing!
Originally published at bizzi-body.com/blog on April 29, 2015.