Как динамически загружать шрифт под iOS. (серьезно)

Я видел, как этот вопрос задавали и отвечали много раз, но я не видел реального ответа. Общие «решения»:

  • Добавьте шрифт в комплект приложения и зарегистрируйте его в файле info.plist.
  • Используйте собственную библиотеку анализа и рендеринга шрифтов (например, FontLabel от Zynga).
  • Это невозможно сделать.

Итак, вопрос: Как динамически загрузить шрифт в iOS? Загрузка шрифта "динамически" означает загрузку любого заданного шрифта, который не известен во время компиляции приложения. .


person Ark-kun    schedule 27.12.2012    source источник
comment
заглянул в CTFontManagerCreateFontDescriptorsFromURL?   -  person Bejmax    schedule 27.12.2012
comment
См. stackoverflow.com/a/12497630/724514. Только что попробовал и смог загрузить и использовать шрифт. В целях загрузки любого шрифта, неизвестного во время компиляции приложения, вы можете загрузить шрифт и сохранить его в каталоге документов, а затем следовать примеру в своем коде.   -  person bobnoble    schedule 27.12.2012


Ответы (6)


Шрифты можно легко динамически загружать из любого места или любого потока байтов. См. статью здесь: 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

person Ark-kun    schedule 27.12.2012
comment
можно ли указать имя для регистрации шрифта как при загрузке? - person user102008; 15.05.2013
comment
@ user102008 Кажется, это невозможно. - person Ark-kun; 15.05.2013
comment
@user102008 вместо получить имя из объекта CGFontRefCGFontCopyFullName. - person adib; 14.02.2016
comment
@adib: я говорил об установке имени, а не о его получении - person user102008; 14.02.2016
comment
можно ли как-то использовать этот метод и с раскадровками/xib? Или все мои пользовательские шрифты должны загружаться при запуске приложения? - person swalkner; 17.05.2016
comment
Шрифт CGFontRef = CGFontCreateWithDataProvider(поставщик); Приложение зависает на этой строке навсегда. (iOS 10.2) - person dev gr; 04.01.2017
comment
Решение найдено на странице stackoverflow.com/questions/ 24900979/ - person dev gr; 04.01.2017

Отличное время для недавней публикации Марко под названием Динамическая загрузка шрифтов iOS.

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);
person shawnwall    schedule 27.12.2012
comment
Это очень забавная ситуация. Я обнаружил сообщение Марко и решил опубликовать этот же код в качестве ответа на кучу вопросов о SO. Но потом я подумал, что было бы лучше создать вопрос с самостоятельным ответом, чтобы ответ было легче найти. Затем модератор удалил мой собственный ответ на мой же вопрос с тем же кодом =( - person Ark-kun; 28.12.2012
comment
можно ли указать имя для регистрации шрифта как при загрузке? - person user102008; 15.05.2013
comment
вам понадобится #import <CoreText/CoreText.h> - person MrTristan; 08.01.2018

Загружаете файл TTF с сервера?

ЕСЛИ вы загружаете файл TTF, вы можете сделать следующее, чтобы зарегистрировать свои пользовательские шрифты в iOS Font Manager, этот фрагмент кода также позаботится об обновлениях файла 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);
}
person dev gr    schedule 07.01.2017

Вот обновленный ответ @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
}
person Gee.E    schedule 04.09.2017

Здесь быстрая версия:

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)");
        }
    }
}
person mt81    schedule 30.03.2016

person    schedule
comment
если вы собираетесь это сделать, почему бы не использовать CTFontManagerRegisterFontsForURL()? - person user102008; 15.05.2013
comment
@ user102008, потому что вы не сможете узнать, какой шрифт вы зарегистрировали по этому URL-адресу. Переход через CGFontRef позволяет вам получить имя и впоследствии использовать обычные методы UIFont. - person adib; 14.02.2016
comment
Если приложение зависает, используйте это: stackoverflow.com/questions /24900979/ - person pegpeg; 16.02.2016