2012-12-27 10 views
13

Ho visto questa domanda posta e ho risposto numerose volte, ma non ho visto una risposta reale. Le "soluzioni" comuni sono:Come caricare dinamicamente un carattere sotto iOS. (per davvero)

  • aggiungere il font al fascio di applicazione e registrarlo nel file Info.plist.
  • Utilizzare una libreria di analisi e rendering di caratteri personalizzati (come la Zynga FontLabel).
  • Non è possibile.

Quindi la domanda è: Come dinamicamente carico un font sotto iOS? Caricare il carattere "dinamicamente" significa caricare un dato font che non è noto al momento della compilazione della app.

+0

guardato in 'CTFontManagerCreateFontDescriptorsFromURL'? – Bejmax

+0

Vedere http://stackoverflow.com/a/12497630/724514. Ho appena provato e sono stato in grado di caricare e utilizzare il carattere. Ai fini del "caricamento di un determinato font non noto al momento della compilazione dell'applicazione", è possibile scaricare il font e salvarlo nella directory Documenti, quindi seguire l'esempio nel codice. – bobnoble

risposta

22

I caratteri possono essere caricati in modo dinamico da qualsiasi posizione o flusso di byte. Vedi l'articolo qui: 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); 
  • Non è necessario mettere il font nel vostro pacco.
  • Non è necessario registrare esplicitamente il carattere nel proprio info.plist.

Consulta anche: 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

è possibile specificare il nome per registrare il carattere come quando si carica? – user102008

+0

@ user102008 Non sembra possibile. –

+0

@ user102008 * richiama * il nome dall'oggetto 'CGFontRef' invece -' CGFontCopyFullName'. – adib

8

grande momento per un recente post di Marco intitolato 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

È una situazione molto divertente. Ho scoperto il post di Marco e sono andato a postare questo stesso codice come risposta a una serie di domande su SO. Ma poi ho pensato che sarebbe stato meglio creare una domanda auto-risposta in modo che la risposta fosse più facilmente individuabile. Quindi il moderatore ha rimosso la mia risposta con la mia stessa domanda con lo stesso codice = ( –

+0

è possibile specificare il nome per registrare il carattere come quando si carica? – user102008

+0

è necessario '#importare ' – 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

se lo farai, perché non usare 'CTFontManagerRegisterFontsForURL()'? – user102008

+0

@ user102008 perché non sarai in grado di sapere qual era il font che hai registrato da quell'URL. Passare tramite 'CGFontRef' ti permette di ottenere nome e utilizzare in seguito i normali metodi 'UIFont'. – adib

+0

Se l'app si blocca, utilizzare questo: http://stackoverflow.com/questions/24900979/cgfontcreatewithdataprovider-hangs-in-airplane-mode – pegpeg

0

Ecco la versione rapida:

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

download di un file TTF da server?

se si sta scaricando un file TTF allora si può fare in seguito per registrare i tuoi font personalizzati con iOS Font Manager, questo pezzo di codice si occupa anche del file di TTF aggiornamenti (aggiornamenti di carattere):

+(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

Qui è una risposta aggiornata di @ mt81 per 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 
} 
Problemi correlati