Как динамически загружать шрифт под iOS. (серьезно)
Я видел этот вопрос и много раз отвечал, но я не видел реального ответа.
Обычными "решениями" являются:
- Добавить шрифт в пакет приложений и зарегистрировать его в файле info.plist.
- Используйте собственную библиотеку разбора шрифтов и рендеринга (например, Zynga FontLabel).
- Это невозможно.
Итак, вопрос: Как динамически загружать шрифт под iOS?
Загрузка шрифта "динамически" означает загрузку любого шрифта, который неизвестен во время компиляции приложения.
Ответы
Ответ 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
Ответ 2
Отличное время для недавнего сообщения от Marco под названием Загрузка шрифтов 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);
Ответ 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]];
}
Ответ 4
Загрузка файла 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);
}
Ответ 5
Здесь быстрая версия:
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)");
}
}
}
Ответ 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
}