Objective-C Runtime使用之全局字體替換為第三方字體

iOS開發(fā)里頭,常用的設(shè)置字體方式是使用UIFont的systemFontOfSize這個(gè)Class Method,在一半情況下都算夠用。

在客戶端中使用特定的字體,我們可以通過手動(dòng)給工程添加配置字體的ttf文件(字體庫)

然后通過fontWithName:name size:size這個(gè) Class Method即可選用,然而在一個(gè)已經(jīng)經(jīng)過長時(shí)間開發(fā)的客戶端,會有歷史遺漏問題

導(dǎo)致整個(gè)工程的字體配置可能存在修改工作量大,改漏改錯(cuò)等情況,針對這種情況我們也可以通過runtime來解決。

1、導(dǎo)入第三方字體

首先需要下載一個(gè).ttf為后綴的文件,也就是字體庫。下載后將文件導(dǎo)入工程,如圖


接著需要在工程配置info.plist中添加這個(gè)字體

在info.plist中添加一行,key是Fonts provided by application,中文意思即 字體由應(yīng)用程序提供

這是個(gè)array對象,那么我們把它展開

往里面添加一個(gè)item,內(nèi)容即我們剛剛添加的那個(gè)文件名

然后在Build Phases里添加資源文件 如圖

接下來可以在工程中,通過UIFont 這個(gè)類 遍歷我們現(xiàn)在可以用的字體集和字體名字

遍歷代碼如下

NSArray *fontFamilys = [UIFont familyNames]; for (NSString *familyName in fontFamilys) { NSLog(@"family name : %@",familyName); NSArray *fontNames = [UIFont fontNamesForFamilyName:familyName]; for (NSString *fontName in fontNames) { NSLog(@"font name : %@",fontName); } }

注意 ,不同的iOS大版本之間,可使用的字體庫會有差異,但是我們這里只需要取到我們手動(dòng)添加的字體

遍歷出來的內(nèi)容很多,不翻頁也不好找到我們添加的字體。我這里添加的字體是微軟雅黑,那么我搜一下也是可以找到的,這里我們需要取font name,即圖上的2016-11-21 09:49:45.780 FontDemo[17853:921926] font name : MicrosoftYaHei取到字體名字,我們就可以通過

[UIFont fontWithName:@"MicrosoftYaHei" size:16];fontWithName: size: 這個(gè)類方法去得到我們需要的UIFont對象,也就是雅黑字體

? ? ?------------------------------華麗的分割線--------------------------

好了,單個(gè)字體的更換這里是實(shí)現(xiàn)了,但是我這里需要的是全局的字體修改接下來的內(nèi)容又要接觸到objc runtime 的method exchange了,也就是method swizzling在Objective-c中,hook方案能解決很多問題,這里的問題是其中之一但是這種全局設(shè)置的方法交換也有一定的局限性,比如 我需要再換其他字體呢? 這個(gè)問題后面再探討開始設(shè)置method swizzling首先 建立一個(gè)UIFont的categroy在.m文件中 實(shí)現(xiàn)load方法,并調(diào)用父類load+ (void)load{ [super load]; }

接著 做method swizzling的過程 只需要調(diào)用一次,那么可以用gcd的once 執(zhí)行,

+ (void)load{?

[super load];

?static dispatch_once_t onceToken;

?dispatch_once(&onceToken, ^{ Method oldMethod = class_getClassMethod([self class], @selector(systemFontOfSize:)); Method newMethod = class_getClassMethod([self class], @selector(__nickyfontchanger_YaheiFontOfSize:)); method_exchangeImplementations(oldMethod, newMethod); });?

}別忘了#import解析一下上面這幾句代碼

首先Method即方法,class_getClassMethod這是獲取類方法,因?yàn)槲覀冊瓉硎褂玫膕ystemFontOfSize是個(gè)類方法。

如果要交換的是實(shí)例方法,那么就要用class_getInstanceMethod 獲取

先獲取舊的方法,再獲取新的方法,新的方法是寫在這個(gè)category里的

像我這里:

+ (UIFont *)__nickyfontchanger_YaheiFontOfSize:(CGFloat)fontSize{ UIFont *font = [UIFont fontWithName:@"MicrosoftYaHei" size:fontSize];?

if (!font)return [self __nickyfontchanger_YaheiFontOfSize:fontSize]; return font; }

再來解析一下這個(gè)方法的執(zhí)行:

首先獲取我們的第三方字體,若字體不存在,則返回系統(tǒng)默認(rèn)字體

但是為什么我返回系統(tǒng)默認(rèn)字體的時(shí)候,調(diào)用的是 [self __nickyfontchanger_YaheiFontOfSize:fontSize]呢?

因?yàn)榉椒ㄒ呀?jīng)交換了,實(shí)際上這個(gè)方法的pointer指向的是系統(tǒng)的systemFontOfSize這個(gè)方法

具體的實(shí)現(xiàn)


單獨(dú)給某個(gè)字體設(shè)置成系統(tǒng)字體怎么辦?

事實(shí)上我們這里只是把兩個(gè)方法交換了而已,所以我們只要把+ (UIFont *)__nickyfontchanger_YaheiFontOfSize:(CGFloat)fontSize;這個(gè)方法寫到.h的聲明里面即可,它實(shí)際就是系統(tǒng)字體

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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