iOS 动态加载字体
2018-12-06 本文已影响17人
MccReeee
- iOS动态加载字体有两种方案
1.加载系统自带字体, 虽然叫系统自带字体, 但还是需要通过网络下载. 系统自带字体下载是由系统完成, 也不会存在app沙盒中. 一次下载永久存储, 除非手机恢复出厂. 但是app使用前需要注册下字体.
具体看代码,注意下载的网络请求会由系统发起,你不需要通过AFNetworking去管理.
+(void)vsc_fontWithPostScriptName:(NSString *)fontName
chsName:(NSString *)chsName
fontSize:(CGFloat)fontSize
progress:(void (^)(CGFloat progress))progress
complete:(void (^)(UIFont *font))complete
failure:(void (^)(NSError *error))failure{
if (!complete) {
return;
}
UIFont *existFont = [self existFontWithPostScriptName:fontName fontSize:fontSize];
if (existFont) {
complete(existFont);
return;
}
//用字体的PostScript名字创建一个Dictionary
NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithObjectsAndKeys:fontName, kCTFontNameAttribute, nil];
// 创建一个字体描述对象CTFontDescriptorRef
CTFontDescriptorRef desc = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attrs);
//将字体描述对象放到一个NSMutableArray中
NSMutableArray *descs = [NSMutableArray arrayWithCapacity:0];
[descs addObject:(__bridge id)desc];
CFRelease(desc);
__block BOOL errorDuringDownload = NO;
//开始对字体进行下载
CTFontDescriptorMatchFontDescriptorsWithProgressHandler( (__bridge CFArrayRef)descs, NULL, ^(CTFontDescriptorMatchingState state, CFDictionaryRef progressParameter) {
CGFloat progressValue = [[(__bridge NSDictionary *)progressParameter objectForKey:(id)kCTFontDescriptorMatchingPercentage] floatValue];
switch (state) {
case kCTFontDescriptorMatchingDidBegin:{//字体已经匹配
}
break;
case kCTFontDescriptorMatchingDidFinish:{//字体下载完成
if (!errorDuringDownload) {
dispatch_async(dispatch_get_main_queue(), ^{
UIFont *font = [UIFont fontWithName:fontName size:fontSize];
complete(font);
});
}
}
break;
case kCTFontDescriptorMatchingWillBeginDownloading:{//字体开始下载
// [self downloadAlertWithPostScriptName:fontName chsName:chsName];
if (needToReask) {
needToReask = NO;
errorDuringDownload = YES;
return (bool)NO;
}
}
break;
case kCTFontDescriptorMatchingDidFinishDownloading:{//字体下载完成
dispatch_async(dispatch_get_main_queue(), ^{
UIFont *font = [UIFont fontWithName:fontName size:fontSize];
complete(font);
});
}
break;
case kCTFontDescriptorMatchingDownloading:{//下载进度
if (progress) {
dispatch_async(dispatch_get_main_queue(), ^{
progress(progressValue);
});
}
}
break;
case kCTFontDescriptorMatchingDidFailWithError:{//下载失败
NSError *error = [(__bridge NSDictionary *)progressParameter objectForKey:(id)kCTFontDescriptorMatchingError];
if (!error) {
error = [NSError errorWithDomain:@"ERROR MESSAGE IS NOT AVAILABLE" code:102 userInfo:nil];
}
errorDuringDownload = YES;
if (failure) {
failure(error);
}
}
break;
default:
break;
}
return (bool)YES;
});
}
- 使用字体时和平时一样, 这里的
fontName
就是刚才下载的fontName
UIFont *font = [UIFont fontWithName:fontName size:18];
self.lab.font = font;
-
那么如何查看我可以下载哪些字体,以及下载的字体具体叫什么名字呢
其实iOS上的字体和macOS上的字体是通用的,并且字体的版权也是一致的,macOS系统上自带的字体iOS上都能用.
所以只要查看macOS上的字体就可以了.
打开macOS,找到系统自带的字体程序
6C2E4A89-E2B9-4CE3-B2EC-02578E020531.jpeg
打开来后是这个样子的,左侧显示字体的名称, 右测红框中显示的就是FontName
image.png
有个注意点,就是app加载过字体后,重新启动可能发现字体没有了,其实字体不是没有,而是没有加载进app,系统虽然下载好了,但是并没有加载进来, 所以建议在AppDelegate启动后再调一次下载字体的函数,让字体从系统加载到app中.
2.方案二,app动态下载字体文件到沙盒,再从沙盒加载. 字体文件是一个后缀为ttf的文件.比如这个.
image.png网络下载就用AFNetworking之类的框架, 我自己是用的YTKNetwork,就像下载文件到本地一样,把字体文件下载到沙盒中.
之后就是加载字体
if ([fontReq existFontName]) {
NSLog(@"字体已存在:%@",fontReq.fontName);
NSString * fontPath = [NSString stringWithFormat:@"%@/%@",Rubick_Document, fontReq.fontName];
;
CGDataProviderRef fontDataProvider = CGDataProviderCreateWithFilename([fontPath UTF8String]);
CGFontRef customfont = CGFontCreateWithDataProvider(fontDataProvider);
CGDataProviderRelease(fontDataProvider);
NSString *fontName = (__bridge NSString *)CGFontCopyFullName(customfont);
CFErrorRef error;
CTFontManagerRegisterGraphicsFont(customfont, &error);
if (error){
// 为了可以重复注册
CTFontManagerUnregisterGraphicsFont(customfont, &error);
CTFontManagerRegisterGraphicsFont(customfont, &error);
}
CGFontRelease(customfont);
UIFont *font = [UIFont fontWithName:fontName size:18];
//给label设置字体
self.lab.font = font;
return;
}
注意, 这里的fontName可能和你想的不太一样
image.png
END