106

We are using custom fonts in our project. It works well in Xcode 5. In Xcode 6, it works in plain text, attributed string in code. But those attributed strings set in storyboard all revert to Helvetica when running on simulator or device, although they look all right in storyboard.

I'm not sure if it's a bug of Xcode 6 or iOS 8 SDK, or the way to use custom fonts is changed in Xcode 6 / iOS 8?

Black Frog
  • 11,595
  • 1
  • 35
  • 66
Allen Hsu
  • 3,515
  • 3
  • 25
  • 38
  • 1
    Same problem here. Would love to know what's up. – obeattie Sep 19 '14 at 09:01
  • 1
    For now, we created a custom UILabel, named GLMarkdownLabel, and exported some properties with IBInspectable, then set markdown strings in storyboard, and translate markdown strings back to attributed strings when awake from nib. – Allen Hsu Sep 28 '14 at 07:13
  • It's now a long term solution, hope Apple will fix this bug in next version of Xcode. – Allen Hsu Sep 28 '14 at 07:13
  • Yikes, such cruft. Thanks for letting us know it's not an isolated issue though. Is there a radar? – obeattie Sep 28 '14 at 20:41
  • Opened one, they closed it as duplicate of 14236279 – yonix Sep 29 '14 at 11:14
  • 1
    Our workaround was eventually going back to using [IBCustomFonts](https://github.com/deni2s/IBCustomFonts) for our attributed labels. – yonix Oct 02 '14 at 07:56
  • Update Xcode 9: Seems like Apple finally solved this (maybe even sooner, but confirmed it works as expected in Xcode 9) – yonix Sep 24 '17 at 11:33

16 Answers16

38

The simplest answer that worked for is to drag the fonts into FontBook. If the fonts are in your project but not in your computer's FontBook, IB sometimes has trouble finding it. Weird, but has worked for me on several occasions.

Alan Scarpa
  • 3,352
  • 4
  • 26
  • 48
  • 18
    While this will let Xcode select the custom font, it doesn't actually work. At runtime the font will not be used like you would expect. – Daniel Apr 14 '16 at 16:31
  • Unfortunately I was not able to come up with a workaround. The best I could do was to log a bug with Apple. – Daniel Jul 25 '16 at 21:10
  • Yes, this is the fix. I had my storyboard designed by another developer, svn update ok, but never got the font in UI. The font was in the resources but not shown in device/simulator UI. Since he uses attributed string, I must have it in Font Book. That solves the problem. – karim Sep 05 '17 at 10:56
  • Yes. this helps me to solve the same problem. When I add custom font into font book things work like charm. – Sushant Jagtap Nov 20 '18 at 07:46
  • 1
    While this solution works on some cases, I also have faced the same issue as @Daniel in the same project with the same font family. XCode needs to sort this issue out. – dey.shin Nov 29 '18 at 16:17
31

The fix for me was to use an IBDesignable class:

import UIKit

@IBDesignable class TIFAttributedLabel: UILabel {

    @IBInspectable var fontSize: CGFloat = 13.0

    @IBInspectable var fontFamily: String = "DIN Light"

    override func awakeFromNib() {
        var attrString = NSMutableAttributedString(attributedString: self.attributedText)
        attrString.addAttribute(NSFontAttributeName, value: UIFont(name: self.fontFamily, size: self.fontSize)!, range: NSMakeRange(0, attrString.length))
        self.attributedText = attrString
    }
}

Giving you this in the Interface Builder:

Interface Builder custom font with attributed string

You can set up your attributedstring just as you normal do, but you'll have to set your fontsize and fontfamily once again in the new available properties.

As the Interface Builder is working with the custom font by default, this results in a what you see is what you get, which I prefer when building apps.

Note

The reason I'm using this instead of just the plain version is that I'm setting properties on the attributed label like the linespacing, which are not available when using the plain style.

Antoine
  • 23,526
  • 11
  • 88
  • 94
  • 1
    Your solution only support one font family and size for a label, then why not just using plain text instead? – Allen Hsu Dec 12 '14 at 07:14
  • Similarly, we're using `@IBInspectable` attributes temporarily, instead of font and size. We have a `markdownText` property, because most of the time, we use attributed string for bold or underlined text. Then parse the markdown text to attributed string with font and size info set for plain text. – Allen Hsu Dec 12 '14 at 07:18
  • @AllenHsu, you're right. Didn't mention that, but I'm using the attributed linespacing for my label. Offcourse, else you would just use the plain style :) – Antoine Dec 12 '14 at 07:47
  • good point, we exported lineSpacing as well :p I think I'd accept your answer since it's actually a bug in Xcode, and there's no better solution for now. Let's wait for next version of Xcode. – Allen Hsu Dec 12 '14 at 07:53
  • may I edit your answer and add our code below to make it more useful? – Allen Hsu Dec 12 '14 at 07:54
  • Offcourse @AllenHsu, we're here to help and bring the best solution possible! – Antoine Dec 12 '14 at 08:03
  • Also if you use single size in whole label, you can get fontSize from font at first character. [attrString attribute:NSFontAttributeName atIndex:0 effectiveRange:nil].pointSize (so no need to specify fontSize as separate attribute) – JakubKnejzlik Aug 20 '15 at 06:46
  • 2
    This won't work if I want to bold a part of the text – xtrinch Apr 25 '16 at 07:48
  • This actually resolved my problem. Remember to notice that you have to drag fonts and drop them onto 'Computer' side menu item. – ZaEeM ZaFaR May 02 '18 at 14:54
  • It's a bug on Xcode 6+ & iOS 8+: http://openradar.appspot.com/radar?id=5117089870249984 – ChavirA Nov 01 '18 at 00:48
23

You can add custom fonts to font book.

Step1: Click on manage fonts. It opens the font book.

enter image description here

Step2: Click on plus and add your fonts.

enter image description here

Next time when you click on font with attributed text newly added font also will show in the list. But make sure your custom font added in info.plist and bundle resources.

5

My solution is a bit of a work around. The real solution is for apple to fix Interface Builder.

With it you can mark all the bold and italic text in interface builder using a system font, then at runtime render your custom font. May not be optimal in all cases.

 NSMutableAttributedString* ApplyCustomFont(NSAttributedString *attributedText,
                     UIFont* boldFont,
                     UIFont* italicFont,
                     UIFont* boldItalicFont,
                     UIFont* regularFont)
{

    NSMutableAttributedString *attrib = [[NSMutableAttributedString alloc] initWithAttributedString:attributedText];
    [attrib beginEditing];
    [attrib enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, attrib.length) options:0
                    usingBlock:^(id value, NSRange range, BOOL *stop)
    {
        if (value)
        {
            UIFont *oldFont = (UIFont *)value;
            NSLog(@"%@",oldFont.fontName);

            [attrib removeAttribute:NSFontAttributeName range:range];

            if([oldFont.fontName rangeOfString:@"BoldItalic"].location != NSNotFound && boldItalicFont != nil)
                [attrib addAttribute:NSFontAttributeName value:boldItalicFont range:range];
            else if([oldFont.fontName rangeOfString:@"Italic"].location != NSNotFound && italicFont != nil)
                [attrib addAttribute:NSFontAttributeName value:italicFont range:range];
            else if([oldFont.fontName rangeOfString:@"Bold"].location != NSNotFound && boldFont != nil)
                [attrib addAttribute:NSFontAttributeName value:boldFont range:range];
            else if(regularFont != nil)
                [attrib addAttribute:NSFontAttributeName value:regularFont range:range];
        }
    }];
    [attrib endEditing];

    return attrib;
}

Inspired by this post

Community
  • 1
  • 1
KidA
  • 66
  • 1
  • 3
5

Thanks to this thread, I've come to this solution:

private let fontMapping = [
    "HelveticaNeue-Medium": "ITCAvantGardePro-Md",
    "HelveticaNeue": "ITCAvantGardePro-Bk",
    "HelveticaNeue-Bold": "ITCAvantGardePro-Demi",
]

func switchFontFamily(string: NSAttributedString) -> NSAttributedString {
    var result = NSMutableAttributedString(attributedString: string)
    string.enumerateAttribute(NSFontAttributeName, inRange: NSRange(location: 0, length: string.length), options: nil) { (font, range, _) in
        if let font = font as? UIFont {
            result.removeAttribute(NSFontAttributeName, range: range)
            result.addAttribute(NSFontAttributeName, value: UIFont(name: fontMapping[font.fontName]!, size: font.pointSize)!, range: range)
        }
    }
    return result
}
rexsheng
  • 161
  • 2
  • 3
4

I have struggled with this bug: UILabel displays correctly in IB with custom font but does not display correctly on device or simulator (font is included in the project and is used in plain UILabels).

Finally found Attributed String Creator on (Mac) App Store. Generates code to be placed in your app in the appropriate place. Fantastic. I am not the creator, just a happy user.

ghr
  • 505
  • 4
  • 8
3

Met the same problem: the attribute font set for TextView in storyboard didn't work in run time with XCode 6.1 & iOS 8 SDK.

This is how I solved this issue, might be a workaround for you:

  1. open the attribute inspector of your textview, change text to "Plain"

  2. click on the cross to delete the "wC hR"(red below)

    enter image description here

  3. change text to "Attributed", and then you can set the font and size for your text.

  4. run to check if it works
Zhihao Yang
  • 1,965
  • 3
  • 16
  • 26
  • It seems that by default there's no `wC hR` property set, neither `UILabel` nor `UITextView`. – Allen Hsu Oct 31 '14 at 04:16
  • by xcode 6, did you set another kind of height-width, like "Regular Width | Any Height", "Compact Width | Regular Height"? because I have a project developed in Xcode 5 and its attributed textview is working even with iOS 8 SDK, I checked there settings and found the only difference is Xcode 6 allows users to set the font for different sizes of devices if you set the text in "Plain". This new configuration might be the reason why setting text in "attributed" but the font is not working. – Zhihao Yang Oct 31 '14 at 09:17
  • 1
    are you using custom fonts? I mean self embedded ones, not system fonts. – Allen Hsu Oct 31 '14 at 09:22
  • Aha, I thought "Custom" fonts you mentioned is the ones offered by Xcode providing it has the font "System". – Zhihao Yang Oct 31 '14 at 09:37
  • It does not work for me. It works for normal string but not for attributed string. – Pratik Somaiya Apr 22 '15 at 11:23
3

Try this it will work

In my case when i try to set "Silversky Technology" as Attributed text for label from interface builder its not show when i run in simulator but its show in interface builder. So i used one trick i made Silversky font with 1 pixel bigger then Technology text.

Attribute text have issue with same size of font so change size of 1 word this thing work with me.

May be this is xcode bug but this trick work for me.

Jignesh Mayani
  • 6,937
  • 1
  • 20
  • 36
2

Met the same problem: the attribute font for UILabel in storyboard didn't work in run time. Using this UIFont+IBCustomFonts.m works for me https://github.com/deni2s/IBCustomFonts

Praveen Sevta
  • 149
  • 1
  • 3
1

The same problem.

Solved: Just check Selectable in TextView. Without this i have standard System font.

Maselko
  • 4,028
  • 2
  • 22
  • 21
1

Double click and install the font to the system. It will work (Xcode 8.2)

1

@Hamidptb solution works, make sure to get the correct name of the font (once you've added it to Font Book)

  • Open the Font Book application, navigate to your font then press Command+I. The PostScript name is the font name you want to use here:

    UILabel.appearance().font = UIFont(name: "PostScriptName", size: 17)

itsmcgh
  • 783
  • 1
  • 9
  • 12
0

I was trying to get tableView cells with text having multiple paragraphs. The attributed strings seemed to be a way to get extra space between the paragraphs (something a bit nicer looking than doing two line-feeds in the string). Came across this and other posts when I discovered that the IB settings didn't apply at run time when you wanted to put different text in the cell.

The main thing I came up with was adding an extension to String (using Swift) to create an attributed string with certain characteristics. Example here uses the Marker Felt font, as it is easily distinguishable from Helvetica. The example also shows a little extra bit of spacing between paragraphs to make them more distinct from each other.

extension String {
func toMarkerFelt() -> NSAttributedString {
    var style = NSMutableParagraphStyle()
    style.paragraphSpacing = 5.0
    let markerFontAttributes : [NSObject : AnyObject]? = [
        NSFontAttributeName : UIFont(name: "Marker Felt", size: 14.0)!,
        NSParagraphStyleAttributeName: style,
        NSForegroundColorAttributeName : UIColor.blackColor()
    ]
    let s = NSAttributedString(string: self, attributes: markerFontAttributes)
    return s
    }
}

Then, in my custom tableViewCell, you send it the text you want and it converts it to an attributed string on the UILabel.

//  MarkerFeltCell.swift
class MarkerFeltCell: UITableViewCell {
@IBOutlet weak var myLabel: UILabel!
func configureCellWithString(inputString : String) {
    myLabel.attributedText = inputString.toMarkerFelt()
}}

In the view controller with the tableView, you should register your cell in viewDidLoad() -- I used a nib, so something like:

let cellName = "MarkerFeltCell"
tableView.registerNib(UINib(nibName: cellName, bundle: nil), forCellReuseIdentifier: cellName)

To get the cell to figure out how tall it should be, make a prototype cell that is used to get size info, and is never added into the tableView. So, in your view controller's variables:

var prototypeSummaryCell : MarkerFeltCell? = nil

Then in (probably override - depending on your view controller) heightForRowAtIndexPath:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        // ...
    if xib == "MarkerFeltCell" {
            if prototypeCell == nil {
                prototypeCell = tableView.dequeueReusableCellWithIdentifier(xib) as? MarkerFeltCell
            }
            let width : CGFloat = tableView.bounds.width
            let height : CGFloat = prototypeCell!.bounds.height
            prototypeCell?.bounds = CGRect(x: 0, y: 0, width: width, height: height)
            configureCell(prototypeCell!, atIndexPath: indexPath)
            prototypeSummaryCell?.layoutIfNeeded()
            let size = prototypeSummaryCell!.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
            let nextHeight : CGFloat = ceil(size.height + 1.0)
            return nextHeight
    } else {  // ...

In the above code, the prototypeCell will be filled in the first time it is needed. The prototypeCell is then used to figure out the height for the cell after going through the autosizing process. You will need to round up the height with the ceil() function. I also added in some extra fudge factor.

The final code bit is how you configure the text for the cell. For this example, simply:

func configureCell(cell :UITableViewCell, atIndexPath indexPath: NSIndexPath) {
    if let realCell = cell as? MarkerFeltCell  {
        realCell.configureCellWithString("Multi-line string.\nLine 2.\nLine 3.")    // Use \n to separate lines
    }
}

Also, here is a shot of the nib. Pinned the label to the edges of the cell (with margin desired), but used a "Greater Than or Equal" constraint, with a less than "Required" priority for the bottom constraint.

Cell constraints

Set the label's font to Attributed. Actual IB font didn't matter.

LabelFont

The result in this case:

CellResults

anorskdev
  • 1,867
  • 1
  • 15
  • 18
0

In case of attributed string you can add custom font in font list as - Click on font icon this will display following dialog .In the following dialog you can add your own category or existing one for custom font.attributed font dialog

After it click on Manage Fonts it open the following dialog select category in you created or existing one . Click on + sign to add font in the category. Manage font dialog

Sunil Singh
  • 538
  • 3
  • 12
0

that's have a simple and quick solition and that's work in my case . that solution is add a code line in didFinishLaunchingWithOptions func in AppDelegate.swift file :

for textViews :

UITextView.appearance().font = UIFont(name: "IranSans", size: 17)

for labels :

UILabel.appearance().font = UIFont(name: "IranSans", size: 17)

and for rest of UiView like this two ☝️

Hamid Reza Ansari
  • 1,107
  • 13
  • 16
0

For anyone applying custom fonts to attributed string in code: Try setting it in viewDidLayoutSubviews. My mistake was doing it in viewDidLoad, it won't be applied there.

serhii.syrotynin
  • 241
  • 1
  • 14