Search code examples
iosswiftnsattributedstringuifontnsmutableattributedstring

NSAttributedString with UIFontWeightTraits


I'm trying to generate a NSAttributedString that has basically just the default font, is italic and a different text color. Easy enough, so far.

Now I want different substrings of this entire string to additionally be bold. It should basically look like this:

from John Smith on 25.08. at 8:00

(Just in a different color.)

It looks like I'm getting the dictionary wrong, that I pass into the NSMutableAttributedString's addAttributes(_:_:) function. From the documentation, I understood that this dictionary should look like this:

[UIFontDescriptorTraitsAttribute: 
    [UIFontWeightTrait: NSNumber(double: Double(UIFontWeightBold))]

But this does not seem to work. All I end up with is the italic version of the string. I'm clearly getting something wrong here. Any idea?

Update: Adding simple example

// Preparation
let rawString = "from John Smith on 25.08. at 8:00"
let attributedString = NSMutableAttributedString(string: rawString)
let nameRange = (rawString as NSString).rangeOfString("John Smith")
let italicFont = UIFont.italicSystemFontOfSize(14)

// Make entire string italic: works!
attributedString.addAttributes([NSFontAttributeName : italicFont], range: NSMakeRange(0, 33))
// Make the name string additionally bold: doesn't work!
attributedString.addAttributes([UIFontDescriptorTraitsAttribute:
        [UIFontWeightTrait: NSNumber(double: Double(UIFontWeightBold))]], range: nameRange)

// Show it on the label
attributedStringLabel.attributedText = attributedString

Thanks!


Solution

  • UIFontDescriptorTraitsAttribute is not a recognized key in the NSAttributedString attributes dictionary, so having obtained the traits you need to reconstruct a UIFont and use the NSFontAttributeName key.

        //prepare the fonts. we derive the bold-italic font from the italic font
        let italicFont = UIFont.italicSystemFontOfSize(14)
        let italicDesc = italicFont.fontDescriptor()
        let italicTraits  = italicDesc.symbolicTraits.rawValue
        let boldTrait = UIFontDescriptorSymbolicTraits.TraitBold.rawValue
        let boldItalicTraits = UIFontDescriptorSymbolicTraits(rawValue:italicTraits | boldTrait)
        let boldItalicDescriptor = italicDesc.fontDescriptorWithSymbolicTraits(boldItalicTraits)
        let boldItalicFont = UIFont(descriptor: boldItalicDescriptor, size: 0.0)
    
        //prepare the string
        let rawString = "from John Smith on 25.08. at 8:00"
        let attributedString = NSMutableAttributedString(string: rawString)
    
        let fullRange = NSMakeRange(0, 33)
        let nameRange = (rawString as NSString).rangeOfString("John Smith")
    
        attributedString.addAttributes([NSFontAttributeName:italicFont], range: fullRange)
        attributedString.addAttributes([NSFontAttributeName:boldItalicFont], range: nameRange)
    

    see also:NSAttributedString: Setting FontAttributes doesn't change font