17

In my app I have a global custom font applied to all labels like so:

UIFont *font = [UIFont fontWithName:kMyFontName size:15.0]; 
[[UILabel appearance] setFont:font];

This works fine. However, in some cases I want to be able to specify a different font for a specific region of a UILabel string.

So I have something like this:

NSString *string = @"Foo Bar Baz";
UIFont *boldFont = [UIFont fontWithName:kMyBoldFontName size:15.0]; 
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:string];
[attrString setAttributes:@{ NSFontAttributeName: boldFont } range:NSMakeRange(0, 3)];
self.myLabel.attributedText = attrString;

However this doesn't seem to work. I expect the "Foo" to be bold, but the entire string just has the default font. It's as if the bold font is not applied at all and is being overwritten by the font set on the UILabel appearance proxy.

When I remove the UILabel appearance line then it works fine (I can see part of the string in bold). Basically I want to have my custom font applied to the label but a separate font applied to a different region of the string. Normally this works fine with attributed strings but for some reason setting the UILabel appearance font disables this functionality (or so it seems).

  • Expected results: "Foo Bar Baz"
  • Actual results: "Foo Bar Baz"

If I remove the [[UILabel appearance] setFont:] line then it works:

  • "Foo Bar Baz"

(but the custom font is not set on the rest of the string).

So my question is: Is there a way to specify a single font to use as the default app-wide but still be able to partially override that using attributed strings?

Also if someone can explain to me why this is not working I'd appreciate it.

nebs
  • 4,939
  • 9
  • 41
  • 70
  • Define "doesn't work". What actually happens? – rmaddy Jul 30 '14 at 04:12
  • @rmaddy Sorry about that, I've updated my question with more details. Let me know if it's still not clear. – nebs Jul 30 '14 at 04:15
  • 1
    Just as a test, try doing: `self.myLabel.font = nil;`. – rmaddy Jul 30 '14 at 04:19
  • @rmaddy interesting suggestion, but that didn't seem to work. – nebs Jul 30 '14 at 04:23
  • have u check custom font have bold font support, becoz some font don't support bold? – falcon143 Jul 30 '14 at 04:35
  • @rmaddy, your comment is the key for my code. I have similar problem, basically I have created my own subclass of UILabel which can dynamically handle styling and stuff. It was working because I initialize everything manually now I have to integrate with XIB and everything is not working anymore. By setting up the font as nil, my attributed string is now working, it's crazy but it's working. Thanks! – V Setyawan Oct 02 '14 at 20:35

3 Answers3

15

Set font and textColor to nil just before setting attributed string.

ksysu
  • 311
  • 4
  • 6
13

You can't mix and match attributed text and plain text; that's why removing the setFont method works - because when you use it, it assumes a plaintext UILabel.

NSString *string = @"Foo Bar Baz";
UIFont *boldFont = [UIFont fontWithName:kMyBoldFontName size:15.0]; 
// Define your regular font
UIFont *regularFont = [UIFont fontWithName:kMyFontName size:15.0];
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:string];
// And before you set the bold range, set your attributed string (the whole range!) to the new attributed font name
[attrString setAttributes:@{ NSFontAttributeName: regularFont } range:NSMakeRange(0, string.length - 1)];
[attrString setAttributes:@{ NSFontAttributeName: boldFont } range:NSMakeRange(0, 3)];
self.myLabel.attributedText = attrString;
brandonscript
  • 68,675
  • 32
  • 163
  • 220
  • That works without the `[UILabel appearance]` font specification (like you said). I would like to keep the global appearance somehow, is that possible? Otherwise I'd have to set the font of each label in the app manually (that includes implicit labels like in buttons and tab bar items). – nebs Jul 30 '14 at 18:19
  • You can't with attributed labels unfortunate, but to keep it easy and consistent, the easiest thing to do is subclass UILabel and define the defaults on init; after, you can just set the changes like you're doing there. – brandonscript Jul 30 '14 at 18:22
  • The range to the end of the string should be (string.length - 1) since the range starts at 0. – Reefwing Oct 30 '15 at 00:09
3

There are two important parts:

  1. UIAppearance applies at the moment of adding UI element to window
  2. labelInstance.font = ... resets all font attributes of currently set attributed string

So if you want to keep UIAppearance customisation you have to set your custom attributed string after your label get added to window.

Reference article about how does UIAppearance work: Peter Steinberger's cool article

Andrew Vyazovoy
  • 580
  • 4
  • 12