不得不说的iOS字体在app中的使用规范

iOS系统家族字体(family font)

系统字体意味着可以不需要另外导入字体包就可以在项目中使用,而且不涉及商用版权问题。

1.系统家族字体

可通过以下代码在控制台打印出系统家族字体的个数和字体名称:

1
2
3
4
5
6
7
8
9
10
11
12

NSArray * nameArray = [UIFont familyNames];

NSLog(@"iOS family font count:%ld",(long)[nameArray count]);

NSLog(@"iOS family font list:\n");

for (NSString *fontName in nameArray) {

NSLog(@"---%@---",fontName);

}

结果:

iOS family font count:75

iOS family font list:

—Copperplate—

—Heiti SC—

—Kohinoor Telugu—

—Thonburi—

—Heiti TC—

—Courier New—

—Gill Sans—

—Apple SD Gothic Neo—

—Marker Felt—

—Avenir Next Condensed—

—Tamil Sangam MN—

—Helvetica Neue—

—Gurmukhi MN—

—Times New Roman—

—Georgia—

—Apple Color Emoji—

—Arial Rounded MT Bold—

—Kailasa—

—Kohinoor Devanagari—

—Kohinoor Bangla—

—Chalkboard SE—

—Sinhala Sangam MN—

—PingFang TC—

—Gujarati Sangam MN—

—Damascus—

—Noteworthy—

—Geeza Pro—

—Avenir—

—Academy Engraved LET—

—Mishafi—

—Futura—

—Farah—

—Kannada Sangam MN—

—Arial Hebrew—

—Arial—

—Party LET—

—Chalkduster—

—Hoefler Text—

—Optima—

—Palatino—

—Lao Sangam MN—

—Malayalam Sangam MN—

—Al Nile—

—Bradley Hand—

—PingFang HK—

—Trebuchet MS—

—Helvetica—

—Courier—

—Cochin—

—Hiragino Mincho ProN—

—Devanagari Sangam MN—

—Oriya Sangam MN—

—Snell Roundhand—

—Zapf Dingbats—

—Bodoni 72—

—Verdana—

—American Typewriter—

—Avenir Next—

—Baskerville—

—Khmer Sangam MN—

—Didot—

—Savoye LET—

—Bodoni Ornaments—

—Symbol—

—Menlo—

—Bodoni 72 Smallcaps—

—Papyrus—

—Hiragino Sans—

—PingFang SC—

—Myanmar Sangam MN—

—Euphemia UCAS—

—Telugu Sangam MN—

—Bangla Sangam MN—

—Zapfino—

—Bodoni 72 Oldstyle—

2.family font的使用

可知,iOS可用的字体共有75种,加上默认系统字体San Francisco,有76种,基本能满足app开发的需求,这些系统提供的字体的使用只需要指定其font name即可。

然而,一些设计师在设计UI时常常使用一些第三方字体,这就需要区别处理。

第三方字体

  1. 必须考虑的问题

遇到需要使用第三字体的情况时,我们需要考虑两方面问题:

  • 导入字体库会增大app占用空间(英文字体一般为几十到几百K,中文字体包大小可能达到十几兆);

  • 第三方字体商用可能涉及商用版权问题(需购买商用版权)。

  1. 如何在项目中使用
  • 先确认商用版权问题

  • 再下载字体包

  • 选择对应的TARGET

  • 选择Build Phases

  • 选择Compile Sources( xxx items ),点击加号添加字体库文件

  • 在info.plist中添加key:”Founts provided by application”,在Value中输入对应第三方字体名称

  • 在需要用到该第三方字体处用[UIFont fontWithName:fontName size:fontSize];引用对应字体

动态下载苹果官方提供字体

从iOS6开始,除了iOS系统提供的字体外,应用程序可以根据需要安装附加字体列表,可供开发者动态下载使用,这些字体只适用于实现下载支持的应用程序,字体以这种方式下载的应用程序没有永久安装,系统可能决定在某些使用场景下删除它们。

我们可以在Mac的Font Book应用中来查看这些附加字体的名称,下载时需要用到其PostScript名称,如下图所示:

获取字体PostScript名称

苹果官方相关说明

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



DESCRIPTION:



Demonstrates how to download fonts on demand on iOS 6 and later.



On iOS 6, we have added the capability for applications to download fonts on demand. Besides the



fonts installed with iOS 6, applications can install a list of additional fonts as necessary. This



list of additional fonts can be found in the following article:



iOS 6: Font list



http://support.apple.com/kb/HT5484



These fonts will only be accessible to applications that implement the download support. Fonts



downloaded from applications in this manner are not installed permanently. The system may decide to



remove them under certain usage scenarios.

官方Demo下载地址

根据官方代码,我们可以很容易地动态下载并在app中使用这些附加字体了。

如果不愿意看官方文档和Demo,现将主要代码总结如下:

异步下载附加字体:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209



- (void)asynchronouslySetFontName:(NSString *)fontName

{

UIFont* aFont = [UIFont fontWithName:fontName size:12.];

// 判断该字体是否已经下载

if (aFont && ([aFont.fontName compare:fontName] == NSOrderedSame || [aFont.familyName compare:fontName] == NSOrderedSame)) {

// 直接使用

NSUInteger sampleIndex = [_fontNames indexOfObject:fontName];

_fTextView.text = [_fontSamples objectAtIndex:sampleIndex];

_fTextView.font = [UIFont fontWithName:fontName size:24.];

return;

}



// 构造字体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);



__block BOOL errorDuringDownload = NO;



// 开始处理字体描述符……

CTFontDescriptorMatchFontDescriptorsWithProgressHandler( (__bridge CFArrayRef)descs, NULL, ^(CTFontDescriptorMatchingState state, CFDictionaryRef progressParameter) {



//NSLog( @"state %d - %@", state, progressParameter);



double progressValue = [[(__bridge NSDictionary *)progressParameter objectForKey:(id)kCTFontDescriptorMatchingPercentage] doubleValue];



if (state == kCTFontDescriptorMatchingDidBegin) {

dispatch_async( dispatch_get_main_queue(), ^ {

// Show an activity indicator

[_fActivityIndicatorView startAnimating];

_fActivityIndicatorView.hidden = NO;



// Show something in the text view to indicate that we are downloading

_fTextView.text= [NSString stringWithFormat:@"Downloading %@", fontName];

_fTextView.font = [UIFont systemFontOfSize:14.];



NSLog(@"Begin Matching");

});

} else if (state == kCTFontDescriptorMatchingDidFinish) {

dispatch_async( dispatch_get_main_queue(), ^ {

// Remove the activity indicator

[_fActivityIndicatorView stopAnimating];

_fActivityIndicatorView.hidden = YES;



// 显示新下载字体的示例文本

NSUInteger sampleIndex = [_fontNames indexOfObject:fontName];

_fTextView.text = [_fontSamples objectAtIndex:sampleIndex];

_fTextView.font = [UIFont fontWithName:fontName size:24.];



// Log the font URL in the console

CTFontRef fontRef = CTFontCreateWithName((__bridge CFStringRef)fontName, 0., NULL);

CFStringRef fontURL = CTFontCopyAttribute(fontRef, kCTFontURLAttribute);

NSLog(@"%@", (__bridge NSURL*)(fontURL));

CFRelease(fontURL);

CFRelease(fontRef);



if (!errorDuringDownload) {

NSLog(@"%@ downloaded", fontName);

}

});

} else if (state == kCTFontDescriptorMatchingWillBeginDownloading) {

dispatch_async( dispatch_get_main_queue(), ^ {

// 显示进度条

_fProgressView.progress = 0.0;

_fProgressView.hidden = NO;

NSLog(@"Begin Downloading");

});

} else if (state == kCTFontDescriptorMatchingDidFinishDownloading) {

dispatch_async( dispatch_get_main_queue(), ^ {

// Remove the progress bar

_fProgressView.hidden = YES;

NSLog(@"Finish downloading");

});

} else if (state == kCTFontDescriptorMatchingDownloading) {

dispatch_async( dispatch_get_main_queue(), ^ {

// 用进度条显示下载进度

[_fProgressView setProgress:progressValue / 100.0 animated:YES];

NSLog(@"Downloading %.0f%% complete", progressValue);

});

} else if (state == kCTFontDescriptorMatchingDidFailWithError) {

// An error has occurred.

// 获取错误信息

NSError *error = [(__bridge NSDictionary *)progressParameter objectForKey:(id)kCTFontDescriptorMatchingError];

if (error != nil) {

_errorMessage = [error description];

} else {

_errorMessage = @"ERROR MESSAGE IS NOT AVAILABLE!";

}

// Set our flag

errorDuringDownload = YES;



dispatch_async( dispatch_get_main_queue(), ^ {

_fProgressView.hidden = YES;

NSLog(@"Download error: %@", _errorMessage"; });

}



return (bool)YES;

});
}

使用系统提供的附加字体,既可以避免商用版权问题,又可以减小应用的体积,适用于多字体样式有要求的应用。

总结

在iOS开发中,我们可能会遇到一些奇怪的UI设计,其中用到好几种非系统库中存在字体,这时我们需要慎重考虑是否要无条件引入第三方字体包,其版权问题和占用空间问题都是十分严重的,需要进一步沟通并确定不存在上述两方面问题时再进行相关开发,否则作为开发者的我们来说会很被动。最后,提醒大家尽量不要使用太多第三方字体,系统提供的字体是用户熟悉了的,app的字体太多反而可能造成用户体验不好,慎之,慎之!!!