How to apply bold and italics to an NSMutableAttributedString range?

Micrified picture Micrified · Dec 28, 2015 · Viewed 20.3k times · Source

I've been trying to apply combinations of NSFontAttributes to NSMutableAttributedString's lately and I simply can't find a thorough explanation on how to do it without removing other attributes.

I've searched a bunch, and found this question pertaining to how to do it with HTML, and then this question about how to find where text has been bolded or italicized, but nothing on how to actually do it.

Currently, I try to format stings as follows:

Italics: [mutableAttributedString addAttribute: NSFontAttributeName value:[fontAttributes valueForKey:CXItalicsFontAttributeName] range:r];

Bold: [mutableAttributedString addAttribute:NSFontAttributeName value:[fontAttributes valueForKey:CXBoldFontAttributeName] range:r];

Where the constants CXItalicsFontAttributeName and CXBoldAttributeName extract the following two values from a dictionary respectfully:

UIFont *italicsFont = [UIFont fontWithName:@"Avenir-BookOblique" size:14.0f];
UIFont *boldFont = [UIFont fontWithName:@"Avenir-Heavy" size:14.0f];

I know this mustn't be the right way to go about formatting, as the NSAttributedString standard attributes don't include a ItalicsFontAttribute or BoldFontAttribute, but I can't find the properly way to do this. Can anyone assist me?

Answer

nyg picture nyg · Jun 22, 2017

In Swift and using an extension:

extension UIFont {

    func withTraits(_ traits: UIFontDescriptor.SymbolicTraits) -> UIFont {

        // create a new font descriptor with the given traits
        guard let fd = fontDescriptor.withSymbolicTraits(traits) else {
            // the given traits couldn't be applied, return self
            return self
        }
            
        // return a new font with the created font descriptor
        return UIFont(descriptor: fd, size: pointSize)
    }

    func italics() -> UIFont {
        return withTraits(.traitItalic)
    }

    func bold() -> UIFont {
        return withTraits(.traitBold)
    }

    func boldItalics() -> UIFont {
        return withTraits([ .traitBold, .traitItalic ])
    }
}

Example:

if let font = UIFont(name: "Avenir", size: 30) {
    let s = NSAttributedString(string: "Hello World!", attributes: [ NSFontAttributeName: font.italic() ])
    let t = NSAttributedString(string: "Hello World!", attributes: [ NSFontAttributeName: font.boldItalic()) ])
}