Last Updated: September 29, 2021
·
3.89K
· kerrishotts

UIFont+Utility

So, I don't know about you, but working with fonts in Objective C on iOS is a pain in the rear end, especially if you're allowing the user to select from more than one font. (Say, an eBook reader.) If you want to get the bold or italicized style of a font, most advice indicates that you should add -Bold or -Italic to the font name.

For example:

NSString *theFontName = @"...";
UIFont *theRegularFont = [UIFont fontWithName:theFontName size:20];
NSString *theBoldFontName = [theFontName stringByAppendingString: @"-Bold"];
UIFont *theBoldFont = [UIFont fontWithName:theBoldFontName size:20];

This works great if your starting font is Helvetica, because there's a corresponding Helvetica-Bold. But what if the font needs -Black for the bold style? Or worse, the regular font needs to be specified as -Roman or -Regular (in which case the bold font is now -Roman-Bold, which likely doesn't exist).

At this point you have a problem: theBoldFont is nil. Which means you can do everything you want to it, but visually the result won't be right. (If anything is displayed at all.)

So the naive approach would be to just add another line:

if (!theBoldFont) theBoldFont = theRegularFont;

Which gets you back to being able to calculate and draw text, but it's not bold! (Of course, not every font has a bold style. But for those that do, it would be nice to use the appropriate bold style.)

Now imagine that you need to conditionally support italics on both the regular and bold font. Ack! Now you have the same issue for each new style, and you're just writing code trying to work around the problem, and not solving it particularly well.

UIFont+Utility to the rescue... or at least, to save you some pain. I'll point you at the gist now so you can take a look at it while we go over some of what it does: https://gist.github.com/kerrishotts/5061352

If you look at the code, the biggest thing you'll notice is that there's a large matrix in there that maps simple font names (like Courier New) to their slighly-more-painful font names you can use with UIFont (CourierNewPSMT). But there's more -- for each font, the matrix also indicates the regular, bold, italic, and bold+italic style. So Courier New + Bold becomes CourierNewPS-BoldMT.

Now, not every font is listed in this matrix -- some for a reason, and some simply because I don't use them. Where a font only has one style, there's no need for it to be listed, because the method will return the original font name. Alternatively, if a font isn't listed that you like to use, you can always add it to the matrix (which would be important if you support a custom font).

So with this utility category, you can do some pretty cool things, but you do need to keep in mind that the mapping is not 100% orthogonal. It tries, but without building a reverse matrix, it's not going to be perfect.

Here's some examples:

*UIFont aFont = [UIFont fontWithName:@"Courier New" andSize:20];
*UIFont bolded = aFont.boldFont;
*UIFont italicized = aFont.italicFont;
*UIFont both = aFont.boldItalicFont;

If the font the utility tries to use doesn't exist, it'll fall back to Helvetica.

You can also do this, if you want a specific fallback font:

*UIFont anotherFont = [UIFont fontWithName:@"Oddball" andSize:20 usingFallback: @"Georgia"];

You can also check if a font is italicized or bolded:

isTheFontItalicized = aFont.isItalicized;
isTheFontBolded = aFont.isBolded;

Now, if you want to avoid using the font creation methods, and just want the font's name, you could use this:

NSString* aBoldFontName = [UIFont fontForFamilyName:@"Helvetica" withAttributes: PKFontBold];

You can also use "fuzzy" attributes:

NSString* aBoldFontName = [UIFont fontForFamilyName:@"Helvetica Bold"];

Something else that usually comes up is a need to increase or decrease the size of a font (say, for a heading):

*UIFont textFont = [UIFont fontWithName:@"Helvetica" andSize:20];
*UIFont headingFont = [textFont fontWithSizeDelta:12];
*UIFont variantFont = [textFont fontWithSizeDeltaPercent:1.25];

The fontWithSizeDelta: method will add the number to the size of the original font - so if you use a negative number, you'll decrease the size of the returned font. The FontWithSizeDeltaPercent: method allows you to scale a font by a certain amount; in the above example the font size is multiplied by 1.25, which returns 25.

Now, all this is nice, but do beware -- this is fresh code, which means I haven't been able to thoroughly test it. It does what I need it to do at the moment, but it may not satisfy your needs. By all means fork it if you need to make changes (or suggest modifications back to the original gist), but just understand that there may be occasions where it doesn't act the way you expect.

Oh, and one last thing: the code is MIT-licensed, so use however you would like.