在iOS开发中使用自定义字体

转载 2015年11月19日 20:57:01

在iOS的项目开发中经常遇到需要使用一些自定义的字体文件,比如仿宋_GB2312、方正小标宋_GBK等。之前我们为了使用这些自定义的字体,在应用的资源包中放入这些字体文件。因为字体文件通常比较大,有的一个字库就达到10M以上(拿方正小标宋_GBK这个字库来说就有13M之多),这样打包后的ipa文件的体积就可能会变得很大,对于只有个别的模块需要特殊的字体样式的应用来说很不划算,那么在iOS6.0以后苹果就开放了动态加载字体的权限。下面就iOS中使用字体的这两种方式进行介绍。

使用静态字体

1、将字体文件拷贝到项目工程中,在Info.plist文件中添加Fonts provided by application的配置项,其中每一个Item对应的是字体文件的名称,如DS-DIGI.TTF

ios_font_static_config.png

2、使用时直接按照如下方式即可:

_textLabel1.font = [UIFont fontWithName:@"DS-Digital" size:40];

效果如下:

ios_font_static_preview.png

3、其他说明:

+ (UIFont *)fontWithName:(NSString *)fontName size:(CGFloat)fontSize;这个方法中需要指定的fontName不是前面设置的字体文件的文件名,而应该是字体的名称,如何获取字体的名称可以通过如下方式:

(1)打印出当前所有可用的字体,查找对应的字体名称

1
2
3
4
5
6
7
8
9
- (void)printAllFonts
{
    NSArray *fontFamilies = [UIFont familyNames];
    for (NSString *fontFamily in fontFamilies)
    {
        NSArray *fontNames = [UIFont fontNamesForFamilyName:fontFamily];
        NSLog (@"%@: %@", fontFamily, fontNames);
    }
}

(2)通过Mac自带的字体册查看字体的名称

直接双击字体即可打开字体册,如果系统没有安装该字体按照要求安装即可,然后可以在字体的详细信息中找到对应的字体的名称:

ios_font_static_fontname.png

使用动态字体

1、动态下载自定义的字体

在网易新闻iOS客户端中可以使用自定义的字体,对于未下载的字体可先下载然后安装下次就能自动设置为该字体,效果如下:

ios_font_dynamic_163news.png

下面就该功能简单介绍实现的步骤

(1)下载指定的字体文件到本地

第一次进入该页面会自动到服务器上获取可使用的字体的列表,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
[
  {
      "fontTitle": "华康圆体",
      "regularName": "DFYuanW3-GB",
      "boldName": "DFYuanW5-GB",
      "author": "华康科技",
      "date": "2012-10-11",
      "fileUrl": "http://xxxx/font/dfgb_y.zip",
      "fileSize": "3.3MB",
      "previewUrl": "http://yyyy/font/ios_yuanti.png"
  }
 ]

上面的内容指明了字体的名称,下载地址等信息,从上面的内容可以看出下载回来的字体文件是一个zip压缩包,再使用前还需要进行解压处理。

1)下载字体文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (NSString *)downloadZipFile:(NSString *)fileUrl toPath:(NSString *)path
{
    NSError *error = nil;
    NSURL *url = [NSURL URLWithString:fileUrl];
    NSString *fileName = [url lastPathComponent];
    NSData *data = [NSData dataWithContentsOfURL:url options:0 error:&error];
    if(!error)
    {
        NSString *zipPath = [path stringByAppendingPathComponent:fileName];
        [data writeToFile:zipPath options:0 error:&error];
        if(!error)
        {
            return zipPath;
        }
    }
    return nil;
}
2)解压zip压缩包

iOS中解压zip压缩文件非常方便,使用ZipArchive这个开源项目按照如下的方式即可快速解压zip文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (NSString *)expandZipFile:(NSString *)src toPath:(NSString *)desc
{
    ZipArchive *za = [[ZipArchive alloc] init];
    if ([za UnzipOpenFile:src])
    {
        BOOL ret = [za UnzipFileTo:desc overWrite:YES];//解压文件
        if(ret)
        {
            NSString *zipName = [src lastPathComponent];//获取zip文件的文件名
            [[NSFileManager defaultManager] removeItemAtPath:zipPath error:nil];//删除zip压缩包
            zipName = [zipName substringToIndex:[zipName rangeOfString:@".zip"].location];//获取解压到的文件夹
            return [self.downloadPath stringByAppendingPathComponent:zipName];
        }
    }
    return nil;
}

ZipArchive项目地址:https://github.com/mattconnolly/ZipArchive

(2)注册指定路径下的字体文件

下载回来的字体文件如果不做处理是不能直接使用的,使用前需要先注册然后才能使用,注册方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void)registerFont:(NSString *)fontPath
{
    NSData *dynamicFontData = [NSData dataWithContentsOfFile:fontPath];
    if (!dynamicFontData)
    {
        return;
    }
    CFErrorRef error;
    CGDataProviderRef providerRef = CGDataProviderCreateWithCFData((__bridge CFDataRef)dynamicFontData);
    CGFontRef font = CGFontCreateWithDataProvider(providerRef);
    if (! CTFontManagerRegisterGraphicsFont(font, &error))
    {
        //注册失败
        CFStringRef errorDescription = CFErrorCopyDescription(error);
        NSLog(@"Failed to load font: %@", errorDescription);
        CFRelease(errorDescription);
    }
    CFRelease(font);
    CFRelease(providerRef);
}

需要先引入#import <CoreText/CoreText.h>CoreText框架。

(3)判断字体是否加载

在使用字体文件前最好是先判断字体是否已经被加载过了,判断方式如下:

1
2
3
4
5
6
- (BOOL)isFontDownloaded:(NSString *)fontName
{
    UIFont* aFont = [UIFont fontWithName:fontName size:12.0];
    BOOL isDownloaded = (aFont && ([aFont.fontName compare:fontName] == NSOrderedSame || [aFont.familyName compare:fontName] == NSOrderedSame));
    return isDownloaded;
}
(4)其他说明

经测试注册过的字体在应用关闭后下次开启应用,判断字体是否加载时返回为NO,为了保证正常使用需要每次启动应用的时候先遍历一遍字体文件夹将里面的字体文件都再次注册一遍即可。参考代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//注册fonts目录下面的所有字体文件
NSArray *ary = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.downloadPath error:nil];
for (NSString *p1 in ary)
{
  NSString *t1 = [self.downloadPath stringByAppendingPathComponent:p1];
  NSArray *ary1 = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:t1 error:nil];
  for (NSString *p1 in ary1)
  {
      NSString *t2 = [t1 stringByAppendingPathComponent:p1];
      if([t2 rangeOfString:@".ttf"].location != NSNotFound)
      {
          [self registerFont:t2];
      }
  }
}

2、动态下载苹果提供的字体

大多数的中文字体是有版权的,在应用中加入特殊中文字体还需要处理相应的版权问题。从iOS6开始,苹果就支持动态下载中文字体到系统中。

(1)苹果支持下载的字体列表

1)iOS6字体列表:http://support.apple.com/zh-cn/HT202599

2)iOS7字体列表:http://support.apple.com/zh-cn/HT5878

(2)官方提供的示例代码

访问https://developer.apple.com/library/ios/samplecode/DownloadFont/Introduction/Intro.html下载示例程序。针对示例程序简单介绍如下:

1)判断字体是否已经被下载过

1
2
3
4
5
UIFont* aFont = [UIFont fontWithName:fontName size:12.];
if (aFont && ([aFont.fontName compare:fontName] == NSOrderedSame || [aFont.familyName compare:fontName] == NSOrderedSame)) {
  // 字体已经被加载过,可以直接使用
  return;
}

2)下载字体

根据字体的PostScript名称构建下载字体所需的参数:

1
2
3
4
5
6
7
8
//使用字体的PostScript名称构建一个字典
NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithObjectsAndKeys:fontName, kCTFontNameAttribute, nil];
//根据上面的字典创建一个字体描述对象
CTFontDescriptorRef desc = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attrs);
//将字体描述对象放到一个数组中
NSMutableArray *descs = [NSMutableArray arrayWithCapacity:0];
[descs addObject:(__bridge id)desc];
CFRelease(desc);

下载字体文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
_block BOOL errorDuringDownload = NO;
CTFontDescriptorMatchFontDescriptorsWithProgressHandler( (__bridge CFArrayRef)descs, NULL,  ^(CTFontDescriptorMatchingState state, CFDictionaryRef progressParameter) {
    //下载的进度    
  double progressValue = [[(__bridge NSDictionary *)progressParameter objectForKey:(id)kCTFontDescriptorMatchingPercentage] doubleValue];
  if (state == kCTFontDescriptorMatchingDidBegin) {
      dispatch_async( dispatch_get_main_queue(), ^ {
          //开始匹配
          NSLog(@"Begin Matching");
      });
  } else if (state == kCTFontDescriptorMatchingDidFinish) {
      dispatch_async( dispatch_get_main_queue(), ^ {
          if (!errorDuringDownload) {
              //字体下载完成
              NSLog(@"%@ downloaded", fontName);
               //TODO:在此修改UI控件的字体样式
          }
      });
  } else if (state == kCTFontDescriptorMatchingWillBeginDownloading) {
      //开始下载
        NSLog(@"Begin Downloading");
        dispatch_async( dispatch_get_main_queue(), ^ {
          //TODO:在此显示下载进度提示
      });
  } else if (state == kCTFontDescriptorMatchingDidFinishDownloading) {
      //下载完成
      NSLog(@"Finish downloading");
      dispatch_async( dispatch_get_main_queue(), ^ {
          //TODO:在此修改UI控件的字体样式,隐藏下载进度提示
      });
  } else if (state == kCTFontDescriptorMatchingDownloading) {
      //正在下载
      NSLog(@"Downloading %.0f%% complete", progressValue);
      dispatch_async( dispatch_get_main_queue(), ^ {
          //TODO:在此修改下载进度条的数值
      });
  } else if (state == kCTFontDescriptorMatchingDidFailWithError) {
      //下载遇到错误,获取错误信息
      NSError *error = [(__bridge NSDictionary *)progressParameter objectForKey:(id)kCTFontDescriptorMatchingError];
      NSLog(@"%@", [error localizedDescription]);
      //设置下载错误标志
      errorDuringDownload = YES;
  }
    return (bool)YES;
});
(3)说明

1)使用动态下载中文字体的API可以动态地向iOS系统中添加字体文件,这些字体文件都是下载到系统的目录中(目录是/private/var/mobile/Library/Assets/com_apple_MobileAsset_Font/),所以并不会造成应用体积的增加,而且可以在多个应用中共享。

2)如何获取字体的PostScript和FontName?可以通过Mac系统自带的字体册来查看。具体请参考前面的步骤。

参考资料

1、《动态下载苹果提供的多种中文字体》

2、《字体加载三种方式》

3、《在iOS程序中使用自定义字体》

iOS中动态下载系统提供的多种中文字体

从iOS6开始,苹果开始支持动态下载官方提供的中文字体到系统中。使用动态下载中文字体的API可以动态的向iOS系统中添加字体,这些字体文件都是下载到系统的目录中,所以并不会造成应用体积的增加。不过,由...

ios字体动态下载

动态下载字体,不仅可以减少APP包的大小,而且字体在iOS系统中是公共的,可共用的...

iOS UIFont中文字体 -- 中文字体包快速查找

最近我司的产品经理要求新版本的APP中的字体格式要新颖,区别于大众APP的字体。需求大过天,开始着手UIFont类设置字体。最终设置来设置去,还是无法和UI达成一致。 在网上查询设置中文字体,像仿宋...

Flex字体篇——动态嵌入字体

概述 Flex编译器,位于flex sdk的bin目录,例如:Flash Builder 4 sdk 3.5 "C:/Program Files/Adobe/Adobe Flash Builder ...
  • hunkcai
  • hunkcai
  • 2010年07月25日 15:40
  • 7086

修改Flex chart中Legend的字体样式

FLEX的图表(CHART)中的Legend 的字体通过直接设置Style 并没有办法改变字体大小. 通过查资料发现了这个方法: 通过派生LegendItem类,并设置Legend的Item...

ios开发中使用自定义字体

在做一些阅读/古文化/文学相关的app时,难免遇到shi'y

iOS开发 - 使用自定义字体

上次有个同事问我,XXapp的字体怎么那么萌啊?我也想要搞个萌哒哒的字体!于是,就有了今天这篇blog. 首先,我们在iOS开发中,苹果给我们提供了许多的字体,当然这里我就不列举啦,都是些英文,小汤表...

iOS开发小结 - 使用自定义字体

APP开发过程中,根据美工的需求可能会用到一些特殊的字体,然而在苹果自带字体中并没有,那就必须我们开发来来实现这些功能呢,下面以冬青黑体简体中文(Hiragino Sans GB)为例子给大家演示一下...

在iOS开发中使用自定义字体

在iOS的项目开发中经常遇到需要使用一些自定义的字体文件,比如仿宋_GB2312、方正小标宋_GBK等。之前我们为了使用这些自定义的字体,在应用的资源包中放入这些字体文件。因为字体文件通常比较大,有的...

在iOS开发中使用自定义字体

转载自:http://git.devzeng.com/blog/using-custom-font-in-ios.html 在iOS的项目开发中经常遇到需要使用一些自定义的字体文件,比如仿宋_GB2...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在iOS开发中使用自定义字体
举报原因:
原因补充:

(最多只允许输入30个字)