iOS7—Day by day—Day22:Downloadable Fonts

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


在iOS中就预先安装了一些字体,但是这并不是完整的。为了能够节省磁盘的映射空间,iOS提供了一种机制用来下载和在运行的时候使用字体。

苹果提供了一组字体,它们可以被许可使用,包括非罗马字体,和一系列在桌面应用程序的字体。从iOS6开始,字体下载的功能已经能够使用了,但是在iOS7中,有一个更加大的字体列表可供使用.

下载字体存储在系统的某个地方——作为一个应用程序开发者,我们并没有权限去访问字体的存储空间。你需要用到的字体有可能已经被另外的程序请求下载了。然而,如果不是这样的话,而且用户也没有网络连接的情况下,所以我们的字体是不可用的。或者当有一个延迟的请求下载字体——我们等到字体可用的时候进行切换?

首先,我们需要在验证下载使用指定字体之前查看如何得到字体的列表,

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

Listing available fonts

下载字体的API并不是TextKit的一部分,而是在底层的CoreText中。这也就是意味着而不是处理Cocoa对象,我们可以看到许多CoreFoundation对象,然后我们可以进行免费的桥接来让生活变得更加的美好。

我们需要使用CoreText中的这个功能CTFontDescriptorCreateMatchingFontDescriptiors,然后我们用它来匹配一个属性kCTFontDownloadableAttribute,这个属性用来表示哪些字体是否可供下载的。

1
2
3
NSDictionary *descriptorOptions = @{(id)kCTFontDownloadableAttribute: @YES};
CTFontDescriptorRef descriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)descriptorOptions);
CFArrayRef fontDescriptors = CTFontDescriptorCreateMatchingFontDescriptors(descriptor, NULL);

第一行,我们创建一个描述属性的NSDictionary——这里我们只指定了我们感兴趣的就是是否能够下载(downloadable).然后使用这个字典来创建一个CTFontDescriptorRef——需要注意的就是在这里我们需要把NSDictionary转成CFDictionaryRef类型——确保通用的桥接模式。最后我们调用一个可以提供给我们符合匹配描述字体的列表。

对于最后一个方法是阻塞的,并且可能需要ige网络的访问,所以我们将会在requestDownloadableFontList方法中进行调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)requestDownloadableFontList {
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
      NSDictionary *descriptorOptions = @{(id)kCTFontDownloadableAttribute: @YES};
      CTFontDescriptorRef descriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)descriptorOptions);
      CFArrayRef fontDescriptors = CTFontDescriptorCreateMatchingFontDescriptors(descriptor, NULL);
      
      dispatch_async(diapatch_get_main_queue(), ^{
          [self fontListDownloadComplete:(NSArray *)CFBridgingRelese(fontDescriptors)];
      });
      
      // Need to release the font descriptor
      CFRelease(descriptor);
  });
}

附带的示例应用程序是一个表格视图,我们现在这些结果第一级显示字体名称。点击其中一个展示一个新的tableview导航控制器显示的所有字体。因此,在顶层,我们fontDownloadListComplete实现以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)fontListDownloadComplete:(NSArray *)fontList {
  // Need to reorganise array into dictionary
  NSMutableDictionary *fontFamilies = [NSMutableDictionary new];
  for (UIFontDescriptor *descriptor in fontList) {
      NSString *fontFamilyName = [descriptor objectForKey:UIFontDescriptorFamilyAttribute];
      NSMutableArray *fontDescriptor = [fontFamilies objectForKey:fontFamilyName];
      if(!fontDescriptors) {
          fontDescriptors = [NSMutableArray new];
          [fontFamilies setObject:fontDescriptors forKey:fontFamilyName];
      }
      [fontDescriptors addObject:desciptor];
  }
  
  _fontList = [fontFamilies copy];
  [self.tableView reloadData];
}

这里我们只是重组字体描述符数组变成一个字典,按照字体家族进行分类。我们这里使用UIFontDescriptor来等级代替CTFontDescriptorRef.

一旦我们归类正确的数据,我们可以重新加载表。设置了tableview数据源,在viewDidLoad中:

1
2
3
4
5
6
7
8
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.title = @"Families";

    [self requestDownloadableFontList];
}

我们运行程序之后就可以看到导航控制器是这个样子的.

 

下一个级别是在导航控制器中指定一个字体的家族,所以,我们需要创建一个NSArray属性来包含字体描述符的集合。我们把这些写在prepareForSegue:方法中:

1
2
3
4
5
6
7
8
9
10
11
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"ShowFamily"]) {
        SCFontViewController *vc = [segue destinationViewController];
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        NSString *fontFamilyName = [_fontList allKeys][indexPath.row];
        NSArray *fontList = _fontList[fontFamilyName];
        vc.fontList = fontList;
        vc.title = fontFamilyName;
    }
}

运行程序,然后进入到第二级别中就可以看到如下的表示:

 

Downloading a font – 下载字体

在最后一个阶段,如果这个字体可用的话,程序就显示这个字体到底看起来是什么样子的。否则就需要自己触发进行下载。

下载的操作对应于handleDownloadPressed:方法,这个功能中我们感兴趣的是CTFontDescriptorMatchFontDescriptorsWithProgressHandler.如果下载字体就需要一个CFArrayRef字体的描述符。它需要一块作为参数提供更新的用户。该方法立即返回,在后台队列上执行操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (IBAction)handleDownloadPressed:(id)sender {
    self.downloadProgressBar.hidden = NO;
    CTFontDescriptorMatchFontDescriptorsWithProgressHandler((CFArrayRef)@[_fontDescriptor],
            NULL,
            ^bool(CTFontDescriptorMatchingState state, CFDictionaryRef progressParameter) {
        double progressValue = [[(__bridge NSDictionary *)progressParameter objectForKey:(id)kCTFontDescriptorMatchingPercentage] doubleValue];
        if (state == kCTFontDescriptorMatchingDidFinish) {
            dispatch_async(dispatch_get_main_queue(), ^{
                self.downloadProgressBar.hidden = YES;
                [self updateView];
            });
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                self.downloadProgressBar.progress = progressValue;
            });
        }
        return (bool)YES;
    });
}

在执行块中,我们提取当前进度的百分比,然后更新进度条。如果state表明当前的下载已经完成,则我们调用updateView.这个方法我们创建用来加载字体的简单字形内容。注意的一点,我们需要在主线程上面更新UI的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)updateView
{
    NSString *fontName = [self.fontDescriptor objectForKey:UIFontDescriptorNameAttribute];
    self.title = fontName;
    UIFont *font = [UIFont fontWithName:fontName size:26.f];
    if(font && [font.fontName isEqualToString:fontName]) {
        self.sampleTextLabel.font = font;
        self.downloadButton.enabled = NO;
        self.detailDescriptionLabel.text = @"Font available";
    } else {
        self.sampleTextLabel.font = [UIFont systemFontOfSize:font.pointSize];
        self.downloadButton.enabled = YES;
        self.detailDescriptionLabel.text = @"This font is not yet downloaded";
    }
}

运行应用程序,现在你就看可以浏览苹果提供的可用的字体列表,并且可以下载它们:

 

 

Conclusion – 总结

下载的字体是一个方便的功能,将允许您定制你的应用程序的外观,而无需许可字体。然而,重要的是要确保你处理用户没有网络连接的情况下,默认字体应该使用什么。

本文翻译自:iOS7 Day-by-Day :: Day 22 :: Downloadable Fonts

 2014-01-26 Sun  iOS7iOS7 Day-by-Day翻译

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值