美文网首页综合
iOS 动态加载字体

iOS 动态加载字体

作者: MccReeee | 来源:发表于2018-12-06 14:21 被阅读17次
    • 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 动态加载字体

        本文链接:https://www.haomeiwen.com/subject/khcocqtx.html