Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The <code>fontDescriptorWithSymbolicTraits:</code> method is actually capable of doing what you want, with the exception of some edge cases in font trait support among the built-in semantic text styles. The key concept here is that this method replaces <em>all</em> symbolic traits on the previous descriptor with the new trait(s). <a href="https://developer.apple.com/Library/ios/documentation/UIKit/Reference/UIFontDescriptor_Class/Reference/Reference.html#//apple_ref/occ/instm/UIFontDescriptor/fontDescriptorWithSymbolicTraits:" rel="noreferrer">The documentation</a> is a bit wishy-washy on this simply stating that the new traits "take precedence over" the old. </p> <p>Bitwise operations are used to add and remove specific traits, but it appears that special care is required when working with a descriptor generated by <code>preferredFontDescriptorWithTextStyle:</code>. Not all fonts support all traits. The headline font, for instance, is weighted according to the user's preferred content size and even if you can strip the descriptor of its bold trait, the matching <code>UIFont</code> will be bold. Unfortunately, this is not documented anywhere so the discovery of any additional nuances is left as an exercise for the reader.</p> <p>The following example illustrates these issues:</p> <pre><code>// Start with a system font, in this case the headline font // bold: YES italic: NO UIFontDescriptor * originalDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleHeadline]; NSLog(@"originalDescriptor bold: %d italic: %d", isBold(originalDescriptor), isItalic(originalDescriptor)); // Try to set the italic trait. This may not be what you expected; the // italic trait is not added. On a normal UIFontDescriptor the italic // trait would have been set and the bold trait unset. // Ultimately it seems that there is no variant of the headline font that // is italic but not bold. // bold: YES italic: NO UIFontDescriptor * italicDescriptor = [originalDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic]; NSLog(@"italicDescriptor bold: %d italic: %d", isBold(italicDescriptor), isItalic(italicDescriptor)); // The correct way to make this font descriptor italic (and coincidentally // the safe way to make any other descriptor italic without discarding its // other traits) would be as follows: // bold: YES italic: YES UIFontDescriptor * boldItalicDescriptor = [originalDescriptor fontDescriptorWithSymbolicTraits:(originalDescriptor.symbolicTraits | UIFontDescriptorTraitItalic)]; NSLog(@"boldItalicDescriptor bold: %d italic: %d", isBold(boldItalicDescriptor), isItalic(boldItalicDescriptor)); // Your intention was to remove bold without affecting any other traits, which // is also easy to do with bitwise logic. // Using the originalDescriptor, remove bold by negating it then applying // a logical AND to filter it out of the existing traits. // bold: NO italic: NO UIFontDescriptor * nonBoldDescriptor = [originalDescriptor fontDescriptorWithSymbolicTraits:(originalDescriptor.symbolicTraits &amp; ~UIFontDescriptorTraitBold)]; NSLog(@"nonBoldDescriptor bold: %d italic: %d", isBold(nonBoldDescriptor), isItalic(nonBoldDescriptor)); // Seems like it worked, EXCEPT there is no font that matches. Turns out // there is no regular weight alternative for the headline style font. // To confirm, test with UIFontDescriptorTraitsAttribute as the mandatory // key and you'll get back a nil descriptor. // bold: YES italic: NO nonBoldDescriptor = [nonBoldDescriptor matchingFontDescriptorsWithMandatoryKeys:nil].firstObject; NSLog(@"nonBoldDescriptor bold: %d italic: %d", isBold(nonBoldDescriptor), isItalic(nonBoldDescriptor)); </code></pre> <p>FYI, the <code>isBold</code> and <code>isItalic</code> functions used above for the sake of brevity could be implemented as follows:</p> <pre><code> BOOL isBold(UIFontDescriptor * fontDescriptor) { return (fontDescriptor.symbolicTraits &amp; UIFontDescriptorTraitBold) != 0; } BOOL isItalic(UIFontDescriptor * fontDescriptor) { return (fontDescriptor.symbolicTraits &amp; UIFontDescriptorTraitItalic) != 0; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. COThat appears to be partially true, in that it works for fonts created by name. Good catch on the documentation, it reads like it gets `|`ed. This isn't working for dynamic type though. The font has the traits `(1<<14 | 1<<1)`. `1<<1` is bold, but anding it out didn't remove the weight. Interestingly `1<<14` is undocumented. I tried building up a new font from `NSFontAttributeName`, pointSize, and traits but it ends up empty.
      singulars
    2. COInteresting, that differs from what I'm seeing (removing bold as shown above works for me) but you're on to something with that `1<<14`. It seems like traits are not applied against a font descriptor created with `preferredFontDescriptorWithTextStyle:` unless that bit is set. The `italicDescriptor` above does not work; seems you have to combine it with `descriptor.symbolicTraits` to have any effect. Updating the response...
      singulars
    3. COUgh, going one step farther I see what you meant... Creating a font from the `nonBoldDescriptor` above still results in a bold font regardless of removing the trait. Do you know whether this problem is unique to the headline font? When italicized it is `.AppleSystemUIItalicHeadline` and otherwise `AppleSystemUIHeadline`, I wonder if there is no regular weight option for that font… Maybe Apple's intention is for you to strip the attributes off of that descriptor and use a named font if you want to customize, I'll have to read up.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload