【问题标题】:UIFontWeightTrait and UIFontDescriptorFamilyAttribute Ignored when creating UIFont from UIFontDescriptor从 UIFontDescriptor 创建 UIFont 时忽略 UIFontWeightTrait 和 UIFontDescriptorFamilyAttribute
【发布时间】:2014-09-14 15:27:43
【问题描述】:

给定以下代码和运行 iOS 7.1 或更高版本的设备:

 NSDictionary *fontTraitsDictionary = @{UIFontWeightTrait : @(-1.0)};
 NSDictionary *attributesDictionary = @{
                                       UIFontDescriptorFamilyAttribute : @"Helvetica Neue", 
                                       UIFontDescriptorTraitsAttribute : fontTraitsDictionary
                                       };
 UIFontDescriptor *ultraLightDescriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:attributesDictionary];
 UIFont *shouldBeAnUltraLightFont = [UIFont fontWithDescriptor:ultraLightDescriptor size:24];

 NSLog(@"%@", shouldBeAnUltraLightFont);

我希望shouldBeAnUltraLightFont 的值是 HelveticaNeue-UltraLight 的一个实例,但实际上它是:

<UICTFont: 0x908d160> font-family: "Helvetica"; font-weight: normal; font-style: normal; font-size: 24.00pt

据我所知,我正在关注 Apple 文档。为什么字体族和字体粗细信息被完全忽略了?

我尝试过的事情

  • 我尝试过其他姓氏,例如 Helvetica、Avenir 等。
  • 我尝试了valid range from -1 to 1 中的其他字体粗细,增量为 0.25

无论这些变化如何,返回的字体始终是正常粗细的 Helvetica 的香草实例。

【问题讨论】:

  • 如果您从字典中删除 UIFontDescriptorTraitsAttribute 键,则生成的字体属于正确的系列(“Helvetica Neue”,而不是“Helvetica”)。可能是一个错误。您似乎更有可能应该使用fontDescriptorWithSymbolicTraits 来获得正确的字体,但UIFontDescriptorSymbolicTraits 缺少light/ultralight 的值。可能是疏忽。
  • 在 8.0b4 Helvetica Neue 返回 (&lt;UICTFont: 0x7b22c690&gt; font-family: "Helvetica Neue"; font-weight: normal; font-style: normal; font-size: 24.00pt),所以有一些进展。
  • 在我看来,您的代码没有任何问题,而是 iOS 中字体的实现。如果 Helvetica Neue 的每个变体实际上都是其自己的正常粗细字体,那么寻找轻量级变体将不会成功。这是 HelveticaNeue-UltraLight 的日志,按名称检索:&lt;UICTFont: 0x7bf91af0&gt; font-family: "HelveticaNeue-UltraLight"; font-weight: normal; font-style: normal; font-size: 16.00pt

标签: ios7 uifont uifontdescriptor uifontweighttrait


【解决方案1】:

我遇到了同样的问题,文档并没有太大帮助。最终我发现使用 family 属性和 face 属性是有效的:

 UIFontDescriptor* desc = [UIFontDescriptor fontDescriptorWithFontAttributes:
        @{
            UIFontDescriptorFamilyAttribute: @"Helvetica Neue",
            UIFontDescriptorFaceAttribute: @"Light"
        }
    ];

【讨论】:

  • 选择面部确实有效,我首先使用了您的建议,然后使用了 'fontDescriptorWithFace' 。面值似乎并没有真正记录在案。
【解决方案2】:

From the docs:

字体特征字典键

以下常量可用作检索字体描述符信息的键 它的特征字典。

NSString *const UIFontSymbolicTrait;
NSString *const UIFontWeightTrait;
NSString *const UIFontWidthTrait;
NSString *const UIFontSlantTrait;

这对我来说就像这些键是专为从字体描述符中获取信息而设计的,而不是设置它。例如,您可以这样做:

UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
CGFloat weight = [traits[UIFontWeightTrait] floatValue];

这会告诉你你得到的字体比正常的重量要重一点。这似乎不如无需给出确切名称就可以要求较轻的字体有用——但这似乎是预期的用途。

【讨论】:

  • if (font.fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold) // 直接测试是否粗体
【解决方案3】:

在寻找粗体或斜体字体时,至少要尊重符号特征。所以这很好用:

+ (UIFont*)fontWithFamily:(NSString*)family bold:(BOOL)bold italic:(BOOL)italic size:(CGFloat)pointSize {
  UIFontDescriptorSymbolicTraits traits = 0;
  if (bold)   traits |= UIFontDescriptorTraitBold;
  if (italic) traits |= UIFontDescriptorTraitItalic;
  UIFontDescriptor* fd = [UIFontDescriptor
                          fontDescriptorWithFontAttributes:@{UIFontDescriptorFamilyAttribute: family,
                                                             UIFontDescriptorTraitsAttribute: @{UIFontSymbolicTrait:
                                                                                                  [NSNumber numberWithInteger:traits]}}];
  NSArray* matches = [fd matchingFontDescriptorsWithMandatoryKeys:
                      [NSSet setWithObjects:UIFontDescriptorFamilyAttribute, UIFontDescriptorTraitsAttribute, nil]];
  if (matches.count == 0) return nil;
  return [UIFont fontWithDescriptor:matches[0] size:pointSize];
}

例如[MyClass fontWithFamily:@"Avenir Next Condensed" bold:YES italic:NO size:12.0f];

我认为这对 OP 没有帮助,他专门寻找带有UIFontWeightTraitlight 字体,但它可能会帮助其他有类似问题的人。

【讨论】:

    【解决方案4】:

    您可以使用 CTFontDescriptorCreateCopyWithVariation,但您必须先找到字体粗细的变体轴标识符。我已经使用这个实现了对 react-native-svg 中可变字体粗细的支持:

    - (CTFontRef)getGlyphFont
    {
        NSString *fontFamily = topFont_->fontFamily;
        NSNumber *fontSize = [NSNumber numberWithDouble:topFont_->fontSize];
    
        NSString *fontWeight = RNSVGFontWeightStrings[topFont_->fontWeight];
        NSString *fontStyle = RNSVGFontStyleStrings[topFont_->fontStyle];
    
        BOOL fontFamilyFound = NO;
        NSArray *supportedFontFamilyNames = [UIFont familyNames];
    
        if ([supportedFontFamilyNames containsObject:fontFamily]) {
            fontFamilyFound = YES;
        } else {
            for (NSString *fontFamilyName in supportedFontFamilyNames) {
                if ([[UIFont fontNamesForFamilyName: fontFamilyName] containsObject:fontFamily]) {
                    fontFamilyFound = YES;
                    break;
                }
            }
        }
        fontFamily = fontFamilyFound ? fontFamily : nil;
    
        UIFont *font = [RCTFont updateFont:nil
                                  withFamily:fontFamily
                                        size:fontSize
                                      weight:fontWeight
                                       style:fontStyle
                                     variant:nil
                             scaleMultiplier:1.0];
    
        CTFontRef ref = (__bridge CTFontRef)font;
    
        int weight = topFont_->absoluteFontWeight;
        if (weight == 400) {
            return ref;
        }
    
        CFArrayRef cgAxes = CTFontCopyVariationAxes(ref);
        CFIndex cgAxisCount = CFArrayGetCount(cgAxes);
        CFNumberRef wght_id = 0;
    
        for (CFIndex i = 0; i < cgAxisCount; ++i) {
            CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes, i);
            if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
                continue;
            }
    
            CFDictionaryRef cgAxisDict = (CFDictionaryRef)cgAxis;
            CFTypeRef axisName = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisNameKey);
            CFTypeRef axisId = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisIdentifierKey);
    
            if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
                continue;
            }
            CFStringRef axisNameString = (CFStringRef)axisName;
            NSString *axisNameNSString = (__bridge NSString *)(axisNameString);
            if (![@"Weight" isEqualToString:axisNameNSString]) {
                continue;
            }
    
            if (!axisId || CFGetTypeID(axisId) != CFNumberGetTypeID()) {
                continue;
            }
            wght_id = (CFNumberRef)axisId;
            break;
        }
    
        if (wght_id == 0) {
            return ref;
        }
        UIFontDescriptor *uifd = font.fontDescriptor;
        CTFontDescriptorRef ctfd = (__bridge CTFontDescriptorRef)(uifd);
        CTFontDescriptorRef newfd = CTFontDescriptorCreateCopyWithVariation(ctfd, wght_id, (CGFloat)weight);
        CTFontRef newfont = CTFontCreateCopyWithAttributes(ref, (CGFloat)[fontSize doubleValue], nil, newfd);
        return newfont;
    } 
    

    https://github.com/react-native-community/react-native-svg/blob/bf0adb4a8206065ecb9e7cdaa18c3140d24ae338/ios/Text/RNSVGGlyphContext.m#L137-L235

    【讨论】:

      【解决方案5】:

      这对我有用:

        [maString
         enumerateAttribute:NSFontAttributeName
         inRange:<-- desired range -->
         options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
         usingBlock:^(id  _Nullable value, NSRange range, BOOL *_Nonnull stop) {
           if (![value isKindOfClass:[UIFont class]]) {
             return;
           }
           UIFontDescriptor *fontDescriptor = ((UIFont *)value).fontDescriptor;
           NSMutableDictionary *traits = [[fontDescriptor.fontAttributes objectForKey:UIFontDescriptorTraitsAttribute] mutableCopy] ?: [NSMutableDictionary new];
           traits[UIFontWeightTrait] = @(UIFontWeightSemibold);
           fontDescriptor = [fontDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorTraitsAttribute : traits}];
           UIFont *semiboldFont = [UIFont fontWithDescriptor:fontDescriptor size:fontDescriptor.pointSize];
           if (semiboldFont) {
             [maString addAttribute:NSFontAttributeName value:semiboldFont range:range];
           }
         }];
      

      【讨论】:

        猜你喜欢
        • 2013-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多