2012-12-27 81 views
13

我已經看到這個問題並且回答了很多次,但我還沒有看到真正的答案。 常見的「解決方案」是:如何在iOS下動態加載字體。 (真實的)

  • 字體添加到應用程序包,並在Info.plist文件註冊。
  • 使用自定義字體解析和渲染庫(如Zynga的FontLabel)。
  • 這是無法完成的。

所以,問題是:如何動態負荷的iOS下的字體? 加載字體「動態」是指加載應用程序編譯時未知的任何給定字體。

+0

看着'CTFontManagerCreateFontDescriptorsFromURL'? – Bejmax

+0

請參閱http://stackoverflow.com/a/12497630/724514。只是試了一下,並能夠加載和使用字體。爲了「加載應用程序編譯時未知的任何給定字體」,您可以下載字體並將其保存在Documents目錄中,然後按照代碼中的示例進行操作。 – bobnoble

回答

22

字體可以很容易地從任何位置或任何字節流動態加載。看到這裏的文章: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

+0

是否可以指定名稱來註冊加載時的字體? – user102008

+0

@ user102008這似乎不可能。 –

+0

@ user102008 *獲取* CGFontRef'對象的名稱,而不是'CGFontCopyFullName'。 – adib

8

大時間最近的文章從馬可·題爲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); 
+2

這是一個非常有趣的情況。我發現了Marco的帖子,併發布了相同的代碼,作爲對SO上一堆問題的答案。但後來我認爲創建一個自我回答的問題可能會更好,以便更容易發現答案。然後主持人刪除了我自己的答案,用我自己的問題用同樣的代碼=( –

+0

是否可以指定名稱來註冊字體,因爲加載時? – user102008

+0

您需要'#import ' – MrTristan

2
// 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]]; 
    } 
+2

如果你要這樣做,爲什麼不使用'CTFontManagerRegisterFontsForURL()'? – user102008

+0

@ user102008,因爲你無法知道你從那個URL註冊的字體是什麼。通過'CGFontRef'去使你能夠獲得然後使用普通的'UIFont'方法。 – adib

+0

如果應用程序掛起,請使用以下命令:http://stackoverflow.com/questions/24900979/cgfontcreatewithdataprovider-hangs-in-airplane-mode – pegpeg

0

這裏迅速版本:

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)"); 
     } 
    } 
} 
1

下載從服務器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); 
} 
0

這裏是@ mt81爲斯威夫特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 
}