UIFontWeightTrait и UIFontDescriptorFamilyAttribute Игнорируется при создании UIFont из UIFontDescriptor
Учитывая следующий код и устройство под управлением 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, насколько я понимаю. Почему семейство шрифтов и информация о весе шрифта полностью игнорируются?
Вещи Ive пробовали
Независимо от этих изменений, возвращаемый шрифт всегда является ванильным экземпляром Helvetica при нормальном весе.
Ответы
Ответ 1
Я столкнулся с той же проблемой, и документация не очень помогла. В конце концов я понял, что с использованием атрибута family в сочетании с обработанным атрибутом лица:
UIFontDescriptor* desc = [UIFontDescriptor fontDescriptorWithFontAttributes:
@{
UIFontDescriptorFamilyAttribute: @"Helvetica Neue",
UIFontDescriptorFaceAttribute: @"Light"
}
];
Ответ 2
Из документов:
Словарь ключей шрифтов
Следующие константы могут использоваться как ключи для извлечения информации о дескрипторе шрифта из его словарь признаков.
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];
Что бы вам показалось, что шрифт, который вы получили, немного тяжелее обычного веса. Это не кажется столь же полезным, как возможность запросить более легкий вес шрифта, не указывая точное имя, но оно, по-видимому, предназначено для использования.
Ответ 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, который специально ищет легкий шрифт с UIFontWeightTrait
, но может помочь другим с аналогичными проблемами.
Ответ 4
Вы можете использовать CTFontDescriptorCreateCopyWithVariation, но сначала вам нужно найти идентификатор оси вариации для веса шрифта. Я реализовал поддержку переменных весов шрифтов в Reaction-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];
}
}];