iOS 动态加载字体

  • 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

你可能感兴趣的:(iOS 动态加载字体)