【问题标题】:How to dynamically load a font under iOS. (for real)如何在 iOS 下动态加载字体。 (真的)
【发布时间】:2012-12-12 11:33:28
【问题描述】:

我已经多次看到这个问题被问和回答,但我还没有看到真正的答案。 常见的“解决方案”是:

  • 将字体添加到应用程序包并在 info.plist 文件中注册。
  • 使用自定义字体解析和渲染库(如 Zynga 的 FontLabel)。
  • 无法做到。

那么问题来了:如何动态在iOS下加载字体? “动态”加载字体意味着加载任何在应用编译时未知的给定字体。

【问题讨论】:

  • 查看了CTFontManagerCreateFontDescriptorsFromURL?
  • stackoverflow.com/a/12497630/724514。刚试了一下,就可以加载和使用字体了。为了“加载应用程序编译时未知的任何给定字体”,您可以下载字体并将其保存在 Documents 目录中,然后按照代码中的示例进行操作。

标签: ios dynamic fonts truetype


【解决方案1】:

字体可以轻松地从任何位置或任何字节流动态加载。在此处查看文章:http://www.marco.org/2012/12/21/ios-dynamic-font-loading

NSData *inData = /* your font-file data */;
CFErrorRef error;
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);
CGFontRef font = CGFontCreateWithDataProvider(provider);
if (! CTFontManagerRegisterGraphicsFont(font, &error)) {
    CFStringRef errorDescription = CFErrorCopyDescription(error)
    NSLog(@"Failed to load font: %@", errorDescription);
    CFRelease(errorDescription);
}
CFRelease(font);
CFRelease(provider);
  • 您不必将字体放入包中。
  • 您不必在 info.plist 中显式注册字体。

另请参阅: https://developer.apple.com/library/mac/#documentation/Carbon/Reference/CoreText_FontManager_Ref/Reference/reference.html#//apple_ref/doc/uid/TP40008278

https://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGFont/Reference/reference.html#//apple_ref/c/func/CGFontCreateWithDataProvider

【讨论】:

  • 加载时可以指定名称来注册字体吗?
  • @user102008 这似乎不可能。
  • @user102008 get 取自 CGFontRef 对象的名称 - CGFontCopyFullName
  • @adib:我说的是设置名称,而不是获取名称
  • 这个方法也可以在storyboards/xib中使用吗?还是必须在应用启动时加载我所有的自定义字体?
【解决方案2】:

Marco 最近发了一篇题为Loading iOS fonts dynamically 的帖子,非常适合。

NSData *inData = /* your decrypted font-file data */;
CFErrorRef error;
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);
CGFontRef font = CGFontCreateWithDataProvider(provider);
if (! CTFontManagerRegisterGraphicsFont(font, &error)) {
    CFStringRef errorDescription = CFErrorCopyDescription(error)
    NSLog(@"Failed to load font: %@", errorDescription);
    CFRelease(errorDescription);
}
CFRelease(font);
CFRelease(provider);

【讨论】:

  • 这是一个非常有趣的情况。我发现了 Marco 的帖子并发布了相同的代码作为对 SO 上的一堆问题的答案。但后来我认为创建一个自我回答的问题可能会更好,这样答案更容易被发现。然后版主用相同的代码删除了我自己对我自己的问题的回答 =(
  • 加载时可以指定名称来注册字体吗?
  • 你需要#import <CoreText/CoreText.h>
【解决方案3】:
// Note : add "CoreText.framework" into your project to support following code

// Put loadCustomFont function inside app delegate or any shared class to access any where in code...

    -(void)loadCustomFont:(NSMutableArray *)customFontFilePaths{

        for(NSString *fontFilePath in customFontFilePaths){

            if([[NSFileManager defaultManager] fileExistsAtPath:fontFilePath]){

                NSData *inData = [NSData dataWithContentsOfFile:fontFilePath];
                CFErrorRef error;
                CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)inData);
                CGFontRef font = CGFontCreateWithDataProvider(provider);
                // NSString *fontName = (__bridge NSString *)CGFontCopyFullName(font);
                if (!CTFontManagerRegisterGraphicsFont(font, &error)) {
                    CFStringRef errorDescription = CFErrorCopyDescription(error);
                    NSLog(@"Failed to load font: %@", errorDescription);
                    CFRelease(errorDescription);
                }
                CFRelease(font);
                CFRelease(provider);
            }
        }
    }

    // Use as follow inside your view controller...

    - (void)viewDidLoad
    {
        [super viewDidLoad];

        // pass all font files name into array which you want to load dynamically...
        NSMutableArray *customFontsPath = [[NSMutableArray alloc] init];
        NSArray *fontFileNameArray = [NSArray arrayWithObjects:@"elbow_v001.ttf",@"GothamRnd-MedItal.otf", nil];

        for(NSString *fontFileName in fontFileNameArray){

            NSString *fileName = [fontFileName stringByDeletingPathExtension];
            NSString *fileExtension = [fontFileName pathExtension];
            [customFontsPath addObject:[[NSBundle mainBundle] pathForResource:fileName ofType:fileExtension]];
        }


        AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        // load custom font into memory...
        [appDel loadCustomFont:customFontsPath];

        // Use font as below
        [lblName setFont:[UIFont fontWithName:@"Elbow v100" size:15.0]];
        [lblName2 setFont:[UIFont fontWithName:@"Gotham Rounded" size:20.0]];
    }

【讨论】:

  • 如果你要这样做,为什么不使用CTFontManagerRegisterFontsForURL()
  • @user102008 因为您将无法知道您从该 URL 注册的字体是什么。通过CGFontRef 可以让您获取名称并在之后使用普通的UIFont 方法。
  • 如果应用挂起,使用这个:stackoverflow.com/questions/24900979/…
【解决方案4】:

这里是快速版本:

let inData: NSData = /* your font-file data */;
let error: UnsafeMutablePointer<Unmanaged<CFError>?> = nil
let provider = CGDataProviderCreateWithCFData(inData)
if let font = CGFontCreateWithDataProvider(provider) {
    if (!CTFontManagerRegisterGraphicsFont(font, error)) {
        if let unmanagedError = error.memory {
            let errorDescription = CFErrorCopyDescription(unmanagedError.takeUnretainedValue())
            NSLog("Failed to load font: \(errorDescription)");
        }
    }
}

【讨论】:

    【解决方案5】:

    正在从服务器下载 TTF 文件?

    如果您正在下载 TTF 文件,那么您可以执行以下操作以使用 iOS 字体管理器注册您的自定义字体,这段代码还负责 TTF 文件更新(字体更新):

    +(void)registerFontsAtPath:(NSString *)ttfFilePath
    {
        NSFileManager * fileManager = [NSFileManager defaultManager];
    
        if ([fileManager fileExistsAtPath:ttfFilePath] == YES)
        {
            [UIFont familyNames];//This is here for a bug where font registration API hangs for forever.
    
            //In case of TTF file update : Fonts are already registered, first de-register them from Font Manager
            CFErrorRef cfDe_RegisterError;
           bool fontsDeregistered = CTFontManagerUnregisterFontsForURL((__bridge CFURLRef)[NSURL fileURLWithPath:ttfFilePath], kCTFontManagerScopeNone, &cfDe_RegisterError);
    
    
            //finally register the fonts with Font Manager,
            CFErrorRef cfRegisterError;
            bool fontsRegistered= CTFontManagerRegisterFontsForURL((__bridge CFURLRef)[NSURL fileURLWithPath:ttfFilePath], kCTFontManagerScopeNone, &cfRegisterError);
    }
    

    【讨论】:

      【解决方案6】:

      这是@mt81 对 Swift 3 的更新答案:

      guard
          let path = "Path to some font file",
          let fontFile = NSData(contentsOfFile: path)
      else {
          print "Font file not found?"
      }
      
      guard let provider = CGDataProvider(data: fontFile)
      else {
          print "Failed to create DataProvider"
      }
      
      let font = CGFont(provider)
      let error: UnsafeMutablePointer<Unmanaged<CFError>?>? = nil
      
      guard CTFontManagerRegisterGraphicsFont(font, error) else {
          guard
              let unError = error?.pointee?.takeUnretainedValue(),
              let description = CFErrorCopyDescription(unError)
          else {
              print "Unknown error"
          }
          print description
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-25
        • 2020-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-10
        • 2012-05-05
        • 2021-03-13
        相关资源
        最近更新 更多