在iOS開發(fā)中使用自定義字體

在iOS的項(xiàng)目開發(fā)中經(jīng)常遇到需要使用一些自定義的字體文件,比如仿宋_GB2312、方正小標(biāo)宋_GBK等。之前我們?yōu)榱耸褂眠@些自定義的字體,在應(yīng)用的資源包中放入這些字體文件。因?yàn)樽煮w文件通常比較大,有的一個(gè)字庫(kù)就達(dá)到10M以上(拿方正小標(biāo)宋_GBK這個(gè)字庫(kù)來說就有13M之多),這樣打包后的ipa文件的體積就可能會(huì)變得很大,對(duì)于只有個(gè)別的模塊需要特殊的字體樣式的應(yīng)用來說很不劃算,那么在iOS6.0以后蘋果就開放了動(dòng)態(tài)加載字體的權(quán)限。下面就iOS中使用字體的這兩種方式進(jìn)行介紹。

###使用靜態(tài)字體

1、將字體文件拷貝到項(xiàng)目工程中,在Info.plist文件中添加Fonts provided by application的配置項(xiàng),其中每一個(gè)Item對(duì)應(yīng)的是字體文件的名稱,如DS-DIGI.TTF。

2、使用時(shí)直接按照如下方式即可:

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

效果如下:

3、其他說明:

+ (UIFont *)fontWithName:(NSString *)fontName size:(CGFloat)fontSize;這個(gè)方法中需要指定的fontName不是前面設(shè)置的字體文件的文件名,而應(yīng)該是字體的名稱,如何獲取字體的名稱可以通過如下方式:

(1)打印出當(dāng)前所有可用的字體,查找對(duì)應(yīng)的字體名稱

- (void)printAllFonts

{

? ? NSArray *fontFamilies = [UIFont familyNames];

? ? for (NSString *fontFamily in fontFamilies)

? ? {

? ? ? ? NSArray *fontNames = [UIFont fontNamesForFamilyName:fontFamily];

? ? ? ? NSLog (@"%@: %@", fontFamily, fontNames);

? ? }

}

(2)通過Mac自帶的字體冊(cè)查看字體的名稱

直接雙擊字體即可打開字體冊(cè),如果系統(tǒng)沒有安裝該字體按照要求安裝即可,然后可以在字體的詳細(xì)信息中找到對(duì)應(yīng)的字體的名稱:

###使用動(dòng)態(tài)字體

####1、動(dòng)態(tài)下載自定義的字體

在網(wǎng)易新聞iOS客戶端中可以使用自定義的字體,對(duì)于未下載的字體可先下載然后安裝下次就能自動(dòng)設(shè)置為該字體,效果如下:

下面就該功能簡(jiǎn)單介紹實(shí)現(xiàn)的步驟

#####(1)下載指定的字體文件到本地

第一次進(jìn)入該頁面會(huì)自動(dòng)到服務(wù)器上獲取可使用的字體的列表,示例如下:

[

{

"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"

}

]

上面的內(nèi)容指明了字體的名稱,下載地址等信息,從上面的內(nèi)容可以看出下載回來的字體文件是一個(gè)zip壓縮包,再使用前還需要進(jìn)行解壓處理。

######1)下載字體文件

- (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這個(gè)開源項(xiàng)目按照如下的方式即可快速解壓zip文件。

- (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項(xiàng)目地址:https://github.com/mattconnolly/ZipArchive

#####(2)注冊(cè)指定路徑下的字體文件

下載回來的字體文件如果不做處理是不能直接使用的,使用前需要先注冊(cè)然后才能使用,注冊(cè)方式如下:

- (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))

? ? {

? ? ? ? //注冊(cè)失敗

? ? ? ? CFStringRef errorDescription = CFErrorCopyDescription(error);

? ? ? ? NSLog(@"Failed to load font: %@", errorDescription);

? ? ? ? CFRelease(errorDescription);

? ? }

? ? CFRelease(font);

? ? CFRelease(providerRef);

}

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

#####(3)判斷字體是否加載

在使用字體文件前最好是先判斷字體是否已經(jīng)被加載過了,判斷方式如下:

- (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)其他說明

經(jīng)測(cè)試注冊(cè)過的字體在應(yīng)用關(guān)閉后下次開啟應(yīng)用,判斷字體是否加載時(shí)返回為NO,為了保證正常使用需要每次啟動(dòng)應(yīng)用的時(shí)候先遍歷一遍字體文件夾將里面的字體文件都再次注冊(cè)一遍即可。參考代碼如下:

//注冊(cè)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、動(dòng)態(tài)下載蘋果提供的字體

大多數(shù)的中文字體是有版權(quán)的,在應(yīng)用中加入特殊中文字體還需要處理相應(yīng)的版權(quán)問題。從iOS6開始,蘋果就支持動(dòng)態(tài)下載中文字體到系統(tǒng)中。

(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下載示例程序。針對(duì)示例程序簡(jiǎn)單介紹如下:

1)判斷字體是否已經(jīng)被下載過

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

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

// 字體已經(jīng)被加載過,可以直接使用

return;

}

2)下載字體

根據(jù)字體的PostScript名稱構(gòu)建下載字體所需的參數(shù):

//使用字體的PostScript名稱構(gòu)建一個(gè)字典

NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithObjectsAndKeys:fontName, kCTFontNameAttribute, nil];

//根據(jù)上面的字典創(chuàng)建一個(gè)字體描述對(duì)象

CTFontDescriptorRef desc = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attrs);

//將字體描述對(duì)象放到一個(gè)數(shù)組中

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) {

? ? //下載的進(jìn)度? ?

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:在此顯示下載進(jìn)度提示

});

} else if (state == kCTFontDescriptorMatchingDidFinishDownloading) {

//下載完成

NSLog(@"Finish downloading");

dispatch_async( dispatch_get_main_queue(), ^ {

//TODO:在此修改UI控件的字體樣式,隱藏下載進(jìn)度提示

});

} else if (state == kCTFontDescriptorMatchingDownloading) {

//正在下載

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

dispatch_async( dispatch_get_main_queue(), ^ {

//TODO:在此修改下載進(jìn)度條的數(shù)值

});

} else if (state == kCTFontDescriptorMatchingDidFailWithError) {

//下載遇到錯(cuò)誤,獲取錯(cuò)誤信息

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

NSLog(@"%@", [error localizedDescription]);

//設(shè)置下載錯(cuò)誤標(biāo)志

errorDuringDownload = YES;

}

? ? return (bool)YES;

});

(3)說明

1)使用動(dòng)態(tài)下載中文字體的API可以動(dòng)態(tài)地向iOS系統(tǒng)中添加字體文件,這些字體文件都是下載到系統(tǒng)的目錄中(目錄是/private/var/mobile/Library/Assets/com_apple_MobileAsset_Font/),所以并不會(huì)造成應(yīng)用體積的增加,而且可以在多個(gè)應(yīng)用中共享。

2)如何獲取字體的PostScript和FontName?可以通過Mac系統(tǒng)自帶的字體冊(cè)來查看。具體請(qǐng)參考前面的步驟。

###參考資料

1、《動(dòng)態(tài)下載蘋果提供的多種中文字體》

2、《字體加載三種方式》

3、《在iOS程序中使用自定義字體》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,024評(píng)論 3 413
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,328評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,878評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,098評(píng)論 0 286
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,616評(píng)論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,554評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,725評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,971評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評(píng)論 1 280
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,339評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,695評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容