该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));
仅供参考,为简洁起见,上面使用的isBold
andisItalic
函数可以实现如下:
BOOL isBold(UIFontDescriptor * fontDescriptor)
{
return (fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold) != 0;
}
BOOL isItalic(UIFontDescriptor * fontDescriptor)
{
return (fontDescriptor.symbolicTraits & UIFontDescriptorTraitItalic) != 0;
}