在界面构建器中使用自定义字体

31

我在这个网站上搜索过,但只找到了未回答的问题。

我将自定义字体加载到了我的xcode项目中,[UIFont fontWithName:@"Laconic-Light" size:19]可以正常工作。但界面构建器不喜欢这种字体。我不能在IB中使用它,因为它总是显示默认字体。有没有办法告诉IB可以使用这种字体?


https://dev59.com/8XA75IYBdhLWcg3wMmGo - benhowdle89
所以它只是坏了...... :P - david
你可以在这里找到一个非常有用的教程:http://www.abdus.me/ios-programming-tips/set-custom-fonts-in-interface-builder/ - abdus.me
这不是重复的问题。这个问题是关于在Interface Builder中使用自定义字体的。可能的重复问题是关于在Interface Builder中使用系统字体的。 - 0xced
在“使用Interface Builder设置UILabel字体时出现Helvetica字体”的问题中,结果证明这是Interface Builder特定版本的一个错误。但是这个解决方案并不适用于这个问题。 - 0xced
显示剩余2条评论
6个回答

63

我在Xcode 4中也遇到了同样的问题。在我的程序中,有很多没有IBOutletsUILabel,所以我采用了以下方法:

首先,将UILabel子类化为CustomFontLabel

然后,覆盖"awakeFromNib"方法

@implementation CustomFontLabel

- (void)awakeFromNib {
    [super awakeFromNib];
    self.font = [UIFont fontWithName:@"CustomFontName" size:self.font.pointSize];
}

@end

最后,在Interface Builder > Identity Inspector中将类更改为CustomFontLabel


1
这实际上会在界面构建器中显示具有正确字体的标签吗?而不仅仅是在应用程序运行时? - Toby
@Toby 只有在运行时才会发生,因为它是一个子类。 - iwasrobbed
3
很难过苹果不帮助开发者……想想用许多不同字体开发应用程序是多么烦人。 - Renato Lochetti
1
苹果正在帮助开发者(在他们的想法中),因为一个拥有20种不同字体的应用程序将会是一个糟糕的用户体验。 - Crake
不错的解决方案,可惜苹果还没有修复 Xcode 中一个明显且令人沮丧的错误。 - d512

5

另一个解决方案是通过子类化UILabel来加载您的自定义字体。然后,您可以在IB中引用它,尽管您仍然无法看到正确的字体。


3
感谢Apple,我们可以在Xcode 6中直接使用自定义字体。
以下是操作步骤:
  1. 将.ttf字体文件添加到您的bundle中。
  2. 在.plist文件中添加字体名称。
  3. 前往xib/storyboard文件,在那里您可以看到您的字体。
如下图所示:enter image description here

3

3

我更喜欢以稍微通用的方式来实现这个,这样可以让您在Interface Builder中调整文本大小,并在运行时简单地替换字体。

我为任何需要设置字体的UIKit元素创建了一个IBCollection属性,然后从IB中连接相应的项目。

@property (strong, nonatomic) IBOutletCollection(id) NSArray *lightFontItems;
@property (strong, nonatomic) IBOutletCollection(id) NSArray *regularFontItems;

在我的视图加载完成后,我使用以下方法之一:
[self setFontName:@"Roboto-Light" onItemsInArray:[self lightFontItems]];
[self setFontName:@"Roboto-Regular" onItemsInArray:[self regularFontItems]];

setLightFontOnItemsInArray:方法的代码如下:

+ (void)setFontName:(NSString *)fontName onItemsInArray:(NSArray *)array;
{
  [array each:^(id item) {
    if (![item respondsToSelector:@selector(setFont:)]) return;
    [item performSelector:@selector(setFont:) withObject:[UIFont fontWithName:fontName size:[[item font] pointSize]]];
  }];
}

3
提醒一下,您可以使用KVC来实现: [self.lightFontItems setValue:[UIFont fontWithName:@"Roboto-Light" size:12] forKey:@"font"]。 (KVC是键值编码的缩写,它是一种在Objective-C中非常常用的机制,用于通过字符串键或路径访问对象属性或成员变量。此处代码片段使用KVC机制将“font”属性设置为指定字体和大小的UIFont对象。) - Barum Rho

1

字体混淆

如果您混淆UIFont类,则解决方案通常很简单。我认为最好选择一个明智的字体,如Helvetica Neue,并覆盖它。这样,您就可以通过拉取映射将整个项目放回标准状态。当我意识到其他人也这样做时,我已经想出了一种混淆来实现这个目标,所以我将其混合在一起。正如NSHipster所说,混淆可能是危险的,但在这种情况下,考虑到UIFont API的绝对简单性,风险非常低。在我的情况下,这是为企业应用程序完成的,因此风险甚至更低。

UIFont+CustomFont.m类别

#import <objc/runtime.h>

static NSString *const kFontMapPlist = @"FontMap";
static NSDictionary *_replacementFontDictionary = nil;



@implementation UIFont (CustomFont)


static void initializeReplacementFonts()
{
    static BOOL initialized = NO;
    if (initialized)
        return;
    initialized = YES;

    // A Plist with a Dictionary from->to font name mapping
    NSURL *replacementFontMapURL = [[NSBundle mainBundle] URLForResource:kFontMapPlist withExtension:@"plist"];
    NSDictionary *replacementFontMap = [NSDictionary dictionaryWithContentsOfURL:replacementFontMapURL];
    [UIFont setReplacementFontDictionary:replacementFontMap];
}

+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        initializeReplacementFonts();

        SEL fontWithNameSizeSelector = @selector(fontWithName:size:);
        SEL swizzledFontWithNameSizeSelector = @selector(clp_fontWithName:size:);
        SwizzleClassMethod([UIFont class], fontWithNameSizeSelector, swizzledFontWithNameSizeSelector);

        SEL fontWithDescriptorSizeSelector = @selector(fontWithDescriptor:size:);
        SEL swizzledfontWithDescriptorSelector = @selector(clp_fontWithDescriptor:size:);
        SwizzleClassMethod([UIFont class], fontWithDescriptorSizeSelector, swizzledfontWithDescriptorSelector);
    });
}

void SwizzleClassMethod(Class class, SEL originalSelector, SEL replacementSelector)
{
    Class clazz = objc_getMetaClass(class_getName(class));

    Method originalMethod = class_getClassMethod(clazz, originalSelector);
    Method replacementMethod = class_getClassMethod(clazz, replacementSelector);

    // Add method if it doesn't eixst
    BOOL didAddMethod =
    class_addMethod(clazz,
                    originalSelector,
                    method_getImplementation(replacementMethod),
                    method_getTypeEncoding(replacementMethod));


    if (didAddMethod) {
        class_replaceMethod(clazz,
                            replacementSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, replacementMethod);
    }
}



#pragma mark - Swizzled font by descriptor and name calls

+ (UIFont *)clp_fontWithDescriptor:(UIFontDescriptor *)descriptor size:(CGFloat)pointSize
{
    NSString *originalFontName = descriptor.fontAttributes[UIFontDescriptorNameAttribute];
    NSString *replacementFontName = _replacementFontDictionary[originalFontName];

    UIFontDescriptor *replacementFontDescriptor = descriptor;
    if (replacementFontName != nil) {
        replacementFontDescriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:@{UIFontDescriptorNameAttribute: replacementFontName}];
    }

    return [self clp_fontWithDescriptor:replacementFontDescriptor size:pointSize];
}

+ (UIFont *)clp_fontWithName:(NSString *)fontName size:(CGFloat)fontSize
{
    NSString *replacementFontName = _replacementFontDictionary[fontName];
    if (replacementFontName == nil) {
        replacementFontName = fontName;
    }

    return [self clp_fontWithName:replacementFontName size:fontSize];
}



#pragma mark - Replacement Dictionary Getter and Setter

+ (NSDictionary *)replacementDictionary
{
    return _replacementFontDictionary;
}

+ (void)setReplacementFontDictionary:(NSDictionary *)replacmentFontDictionary
{
    if (replacmentFontDictionary == _replacementFontDictionary) {
        return;
    }

    _replacementFontDictionary = replacmentFontDictionary;

    // Validate font existence.
    for (NSString *originalFontName in [_replacementFontDictionary allKeys]) {
        NSString *replacementFontName = [_replacementFontDictionary objectForKey:originalFontName];
        UIFont *replacementFont = [UIFont fontWithName:replacementFontName size:10.0f];
        if (replacementFont == nil) {
            DDLogError(@"WARNING: replacement font '%@' is not available.", replacementFontName);
        }
    }
}

@end

FontMap.plist 文件

为了简化说明,我们假设有一种名为 CustomSans 的字体。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>HelveticaNeue-Light</key>
    <string>CustomSans-Light</string>
    <key>HelveticaNeue-LightItalic</key>
    <string>CustomSans-LightItalic</string>
    <key>HelveticaNeue-Bold</key>
    <string>CustomSans-Bold</string>
    <key>HelveticaNeue-BoldItalic</key>
    <string>CustomSans-BoldItalic</string>
</dict>
</plist>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接