Emoji + Custom fonts != Love

  • Articles
  • iOS
  • Mobile

So you’ve just added a fancy custom font to your application and you’re really happy with how it looks. You’ve created your awesome app, finished all the layouts and UI elements, and then based on some user input (entering a title for something, or a comment on a photo, or whatever your app does) you get some Emoji’s inside your perfectly sized UILabels.

They’ve come to mess up your Feng Shui, all their little yellow heads are cut off, they overlap each other if there are two or more lines of text, a lot of nasty stuff. Oh the horror!

emoji1

You make yourself a fresh cup of coffee and think about how you can fix this. Should you go back into the storyboards and code and start increasing the height of every UILabel that could possible contain emojis? But that probably won’t fix the overlap from the multiple lines of text. Should you just give up on using your fancy custom font and go back to Helvetica? Never!

What you could do is try to change the font size of just those emoji characters. To do that would mean to use NSAttributedString instead of just NSString but it’s way better and quicker than the other ideas. We’ll create a category over NSString that will allow us to get a NSAttributedString with lower font sizes for the emoji characters.

We first need to find out where the emojis are inside the NSString. For that we’ll create a function that will return a NSArray that contains the NSRange for the emojis:

Then we create another function that will use these NSRanges and create the NSAttributedString and set the font attribute for the emojis to a font smaller by 3 points:

So all you need to do now is instead of calling:

self.chatTitleLabel.text = chat.name;

we’ll call:

self.chatTitleLabel.attributedText = [chat.name attributedStringWithFixedEmojisForFont:self.chatTitleLabel.font];

emoji2

But that’s not all! If you go and try this now you might see that sometimes the text will start to shrink progressively, each time your UITableView is refreshed or each time you set a different text to the UILabel.

It might seem crazy at first but apparently when you set the attributedText property on an UILabel, it will change the entire UILabel’s font to that of the first character in your NSAttributedString. And because we’re using the UILabel’s own font size to calculate the font size of the emojis, it ends up shrinking more and more. So if you start with a font size of 15, because we set the emojis to have a font lower by 3 points, the next time you set the attributedText property your UILabel might have a font of 12. Then the next time it will have a font of 9, and so on.

emoji3

emoji4

emoji5

emoji6

 

To fix this we’re going to have to make sure that the first character in the NSAttributedString will have the correct font size, but what can we use and still have the string look exactly the same? After a quick search, we’ve found an Unicode character called “ZERO WIDTH SPACE” with a code of “\u200B”.

We can insert this character as the first character in the NSAttributedString that we generate. We’ll also have to move the emojis NSRange location over by 1, because we inserted that character and everything got shifted to the right.
So our function inside the NSString category will look like this:

Ok. Now we’re done, it should all look fine now. But what if we’re too lazy to go through all the code and replace all of our label.text = someString; with label.text = [someString attributedStringWithFixedEmojisForFont:someFont];

We can create a category over UILabel and every time the setText function is called, we’ll actually call our setAttributedText instead. Let’s swizzle that shizzle! 😎

 

Author:

Răzvan Chichirău