取消绑定UIFontDescriptor

Bri*_*kel 8 objective-c uifont ios ios7

我在应用程序中使用动态类型,并且有我想要更改字体外观的场景,例如使其变为斜体或取消绑定.添加样式很容易:

UIFontDescriptor *descriptor = [[UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleHeadline]
                                fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic];
UIFont *font = [UIFont fontWithDescriptor:descriptor size:descriptor.pointSize];
Run Code Online (Sandbox Code Playgroud)

然而,没有明确的机制去除风格.我可以尝试调整属性,但它们看起来更令人生畏,完全没有文档的API:

Regular Headline: {
    NSCTFontUIUsageAttribute = UICTFontTextStyleHeadline;
    NSFontNameAttribute = ".AppleSystemUIHeadline";
    NSFontSizeAttribute = 17;
}

Italic Headline: {
    NSCTFontUIUsageAttribute = UICTFontTextStyleItalicHeadline;
    NSFontNameAttribute = ".AppleSystemUIItalicHeadline";
    NSFontSizeAttribute = 17;
}
Run Code Online (Sandbox Code Playgroud)

我还缺少另一条途径吗?我可以使用,[UIFont systemFontWithSize:descriptor.pointSize]但我不想丢失动态类型提供的任何绘图规则.

ipa*_*son 27

fontDescriptorWithSymbolicTraits:除了内置语义文本样式中字体特征支持的一些边缘情况之外,该方法实际上能够执行您想要的操作.这里的关键概念是该方法用新特征替换先前描述符上的所有符号特征.这篇文章有点过于谨慎,仅仅说明新特征"优先于旧".

按位运算用于添加和删除特定的特征,但在处理生成的描述符时似乎需要特别小心preferredFontDescriptorWithTextStyle:.并非所有字体都支持所有特征.例如,标题字体根据用户的首选内容大小进行加权,即使您可以删除其粗体特征的描述符,匹配UIFont也将是粗体.不幸的是,这在任何地方都没有记载,所以任何其他细微差别的发现都留给读者练习.

以下示例说明了这些问题:

// 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 & ~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));
Run Code Online (Sandbox Code Playgroud)

仅供参考,为简洁起见,上面使用的函数isBoldisItalic函数可以实现如下:

 BOOL isBold(UIFontDescriptor * fontDescriptor)
 {
    return (fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold) != 0;
 }

 BOOL isItalic(UIFontDescriptor * fontDescriptor)
 {
    return (fontDescriptor.symbolicTraits & UIFontDescriptorTraitItalic) != 0;
 }
Run Code Online (Sandbox Code Playgroud)

  • "使用带有文本工具包的字体"WWDC会话揭示了这里可能发生的事情.在视频中的18:00左右,在PDF中滑动18,注意到`fontDescriptorWithSymbolicTraits:`在内部执行字体匹配过程.它只能给你一个实际匹配字体的描述符.这就解释了为什么上面的'italicDescriptor`不起作用; 没有标题字体的变体是斜体但不是粗体.最终动态类型根据内容大小控制标题字体的权重,因此您显然无法更改. (6认同)