iOS:在运行时编程添加自定义字体

16
我想允许我的应用程序用户在应用中使用自己的字体,通过将它们复制到文档目录(通过iTunes)。然而,我找不到一种使用自定义字体的方法,因为正确的方法取决于在应用程序的 Info.plist 中使用 UIAppFonts 关键字。
是否有一种在运行时覆盖此设置的方法?
谢谢。
4个回答

19

我知道这是一个老问题,但我今天也在尝试做同样的事情,并且发现可以使用CoreText和CGFont来实现。

首先确保您添加了CoreText框架和

#import <CoreText/CoreText.h>

那么这应该就可以了(在这个示例中,我使用了之前下载并保存到“文档”目录中的字体):

NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * documentsDirectory = [paths objectAtIndex:0];
    NSString * fontPath = [documentsDirectory stringByAppendingPathComponent:@"Fonts/Chalkduster.ttf"];
    NSURL * url = [NSURL fileURLWithPath:fontPath];
    CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)url);
    CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider);
    NSString * newFontName = (__bridge NSString *)CGFontCopyPostScriptName(newFont);
    CGDataProviderRelease(fontDataProvider);
    CFErrorRef error;
    CTFontManagerRegisterGraphicsFont(newFont, &error);
    CGFontRelease(newFont);

    UIFont * finalFont = [UIFont fontWithName:newFontName size:20.0f];

希望这能帮到任何遇到这个问题的人!


你好,我有一个问题.. 实际上,在运行时,我从 Web 服务中获取字体,那么我可以安装并使用它吗?如何操作? - Hardik Vyas
你可以将它保存到你的应用程序文档目录中,然后使用上面的代码进行加载。 - Pablo
CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider); 应用程序在这一行上永远挂起。 - dev gr

6
尝试这个。
#import "MBProgressHUD.h"
#import <CoreText/CoreText.h>


- (void)viewDidLoad
{
    NSURL *fileNameURL=[NSURL URLWithString:@"http://www.ge.tt/api/1/files/6d7jEnk/0/"];
    NSMutableURLRequest *filenameReq=[[NSMutableURLRequest alloc] initWithURL:fileNameURL];
    NSData *responseData=[NSURLConnection sendSynchronousRequest:filenameReq returningResponse:nil error:nil];

    NSDictionary* json = [NSJSONSerialization
                          JSONObjectWithData:responseData
                          options:kNilOptions
                          error:nil];


    NSString *fontFileName=[[[json valueForKey:@"filename"] componentsSeparatedByString:@"."] objectAtIndex:0];

    NSLog(@"file name is %@",fontFileName);

    NSURL *url=[NSURL URLWithString:@"http://www.ge.tt/api/1/files/6d7jEnk/0/blob?download"];

    NSMutableURLRequest *request=[[NSMutableURLRequest alloc] initWithURL:url];

    __block NSError *error;
    __block NSURLResponse *response;

    MBProgressHUD *hud=[MBProgressHUD showHUDAddedTo:self.view animated:YES];
    hud.labelText=@"Changing Font..";

    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{

        NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

        NSString *rootPath=[NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents"]];
        NSString *filePath=[rootPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.ttf",fontFileName]];

        dispatch_async(dispatch_get_main_queue(), ^{
            [MBProgressHUD hideAllHUDsForView:self.view animated:YES];

            NSFileManager *fm=[NSFileManager defaultManager];

            if (![fm fileExistsAtPath:filePath]) {
                [urlData writeToFile:filePath atomically:YES];
            }

            NSString *rootPath=[NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents"]];
            NSString *filePath=[rootPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.ttf",fontFileName]];

            NSURL * fonturl = [NSURL fileURLWithPath:filePath];
            CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)fonturl);

            CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider);
            NSString * newFontName = (__bridge NSString *)CGFontCopyPostScriptName(newFont);
            CGDataProviderRelease(fontDataProvider);
            CFErrorRef fonterror;
            CTFontManagerRegisterGraphicsFont(newFont, &fonterror);

            CGFontRelease(newFont);

            UIFont * finalFont = [UIFont fontWithName:newFontName size:20.0f];

            [txt_UserName setFont:finalFont];
        });
    });

    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

这里有样例代码

它的样子会像这样

在此输入图片描述


1

Zynga的开发人员创建了一个类,使得加载任何自定义字体成为可能:FontLabel

您必须在应用程序启动时调用[FontManager loadFont:](例如在应用程序委托中)以便每个您想在应用程序中使用的字体都能够被加载。

因此,在文档文件夹中查找.ttf文件(该库仅适用于ttf字体)并进行迭代是非常棘手的。

一个小提示:这个类使用UILabel的子类。


当我点击那个链接时,出现了404错误。 - Victor Engel

1
extension UIFont {

    func registerNewFontFromAppBundle(withSize: CGFloat) {
        guard let filePath = Bundle.main.url(forResource: "Art Brewery", withExtension: "ttf") else { return }
        guard let dataProvider = CGDataProvider(url: filePath as CFURL), let cgFont = CGFont(dataProvider) else { return }

        var error: Unmanaged<CFError>?
        if !CTFontManagerRegisterGraphicsFont(cgFont, &error)
        {
            print("Error registering Font")
        } else {
            guard let uiFont = UIFont(name: cgFont.postScriptName! as String, size: withSize) else { return  }
            CurrentTheme.shared.currentFont = uiFont
        }
    }

    func registerNewFontFromDownloadedFiles(withSize: CGFloat) {
         guard let filePath = FileUtils().getFilePathAtDocumentFolder(fileName: "Art Brewery.ttf") else { return }

        if FileUtils.fileExists(atPath: filePath) {
          let url = URL(fileURLWithPath: filePath)
        guard let dataProvider = CGDataProvider(url: url as CFURL), let cgFont = CGFont(dataProvider) else { return }

        var error: Unmanaged<CFError>?
        if !CTFontManagerRegisterGraphicsFont(cgFont, &error)
        {
            print("Error registering Font")
        } else {
            guard let uiFont = UIFont(name: cgFont.postScriptName! as String, size: withSize) else { return  }
            CurrentTheme.shared.currentFont = uiFont
            CurrentTheme.shared.currentFontName = cgFont.postScriptName! as String
        }
    }

    }
}

使用方法:

UIFont.registerNewFontFromAppBundle(withSize: 30)
UIFont.registerNewFontFromDownloadedFiles(withSize: 30)
mylabel.font =  CurrentTheme.shared.currentFont // saved the font in a Singleton
or 
mylabel.font = UIFont(name: CurrentTheme.shared.currentFontName, size: 30) // Saved the Font name to reuse

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