前言:

  iOS开发里头,常用的设置字体方式是使用UIFont的systemFontOfSize这个Class Method,在一半情况下都算够用。

最近有设计师朋友问能不能在客户端中使用特定的字体,答案是可以的,我们可以通过手动给工程添加配置字体的ttf文件(字体库)

然后通过fontWithName:name size:size这个 Class Method即可选用,然而在一个已经经过长时间开发的客户端,会有历史遗漏问题

导致整个工程的字体配置可能存在修改工作量大,改漏改错等情况,针对这种情况我们也可以通过runtime来解决。

1、导入第三方字体

首先需要下载一个.ttf为后缀的文件,也就是字体库。下载后将文件导入工程,如图

接着需要在工程配置info.plist中添加这个字体

在info.plist中添加一行,key是Fonts provided by application,中文意思即 字体由应用程序提供

这是个array对象,那么我们把它展开

往里面添加一个item,内容即我们刚刚添加的那个文件名

然后在Build Phases里添加资源文件 如图

接下来可以在工程中,通过UIFont 这个类 遍历我们现在可以用的字体集和字体名字

遍历代码如下

  1. NSArray *fontFamilys = [UIFont familyNames];
  2. for (NSString *familyName in fontFamilys) {
  3. NSLog(@"family name : %@",familyName);
  4. NSArray *fontNames = [UIFont fontNamesForFamilyName:familyName];
  5. for (NSString *fontName in fontNames) {
  6. NSLog(@"font name : %@",fontName);
  7. }
  8. }

注意 ,不同的iOS大版本之间,可使用的字体库会有差异,但是我们这里只需要取到我们手动添加的字体

遍历出来的内容很多,不翻页也不好找到我们添加的字体。

我这里添加的字体是微软雅黑,那么我搜一下

也是可以找到的,这里我们需要取font name,即图上的2016-11-21 09:49:45.780 FontDemo[17853:921926] font name : MicrosoftYaHei

取到字体名字,我们就可以通过

  1. [UIFont fontWithName:@"MicrosoftYaHei" size:];

fontWithName: size: 这个类方法去得到我们需要的UIFont对象,也就是雅黑字体

------------------------------不华丽的分割线--------------------------

好了,单个字体的更换这里是实现了,但是我这里需要的是全局的字体修改

接下来的内容又要接触到objc runtime 的method exchange了,也就是method swizzling

在Objective-c中,hook方案能解决很多问题,这里的问题是其中之一

但是这种全局设置的方法交换也有一定的局限性,比如 我需要再换其他字体呢? 这个问题后面再探讨

开始设置method swizzling

首先 建立一个UIFont的categroy

在.m文件中 实现load方法,并调用父类load

  1. + (void)load{
  2. [super load];
  3. }

接着 做method swizzling的过程 只需要调用一次,

那么可以用gcd的once 执行,

  1. + (void)load{
  2. [super load];
  3. static dispatch_once_t onceToken;
  4. dispatch_once(&onceToken, ^{
  5. Method oldMethod = class_getClassMethod([self class], @selector(systemFontOfSize:));
  6. Method newMethod = class_getClassMethod([self class], @selector(__nickyfontchanger_YaheiFontOfSize:));
  7. method_exchangeImplementations(oldMethod, newMethod);
  8. });
  9. }

别忘了#import <objc/runtime.h>

解析一下上面这几句代码

首先Method即方法,class_getClassMethod这是获取类方法,因为我们原来使用的systemFontOfSize是个类方法。

如果要交换的是实例方法,那么就要用class_getInstanceMethod 获取

先获取旧的方法,再获取新的方法,新的方法是写在这个category里的

像我这里:

  1. + (UIFont *)__nickyfontchanger_YaheiFontOfSize:(CGFloat)fontSize{
  2. UIFont *font = [UIFont fontWithName:@"MicrosoftYaHei" size:fontSize];
  3. if (!font)return [self __nickyfontchanger_YaheiFontOfSize:fontSize];
  4. return font;
  5. }

再来解析一下这个方法的执行:

首先获取我们的第三方字体,若字体不存在,则返回系统默认字体

但是为什么我返回系统默认字体的时候,调用的是 [self __nickyfontchanger_YaheiFontOfSize:fontSize]呢?

因为方法已经交换了,实际上这个方法的pointer指向的是系统的systemFontOfSize这个方法

具体的实现

那么再运行一下工程看看?

ps:问题来了

我要单独给某个字体设置成系统字体怎么办?

事实上我们这里只是把两个方法交换了而已,所以我们只要把+ (UIFont *)__nickyfontchanger_YaheiFontOfSize:(CGFloat)fontSize;这个方法写到.h的声明里面即可,它实际就是系统字体

如有错误欢迎更正





Objective-C Runtime使用之全局字体替换为第三方字体(iOS)的更多相关文章

  1. iOS运用runtime全局修改UILabel的默认字体

    iOS运用runtime全局修改UILabel的默认字体 一.需求背景介绍 在项目比较成熟的基础上,遇到了这样一个需求,应用中需要引入新的字体,需要更换所有Label的默认字体,但是同时,对于一些特殊 ...

  2. 帝国时代II 高清版 steam 4.4 字体替换 微软雅黑

    其实默认的中文字体算是中规中矩吧,但是我并不喜欢 从昨天开始就想着换 于是我就开始搜索帝国时代2的游戏目录的资源,马上就锁定到了\Steam\steamapps\common\Age2HD\resou ...

  3. Android 全局使用第三方字体

    给APP全局设置字体主要分为两个方面来介绍 一.给原生界面设置第三方字体 1.准备工作-下载第三方字体:传送门 将文件放入工程assets目录下.(一般个人习惯单独命名一个文件夹放字体文件,也可直接放 ...

  4. 基于C#简单实现多个word文件和Excel文件的全局字符串替换

    公司整理文档工作中,出现了一个需要使用全局字符替换多个word文档.excel文档中的内容的需求.虽然office.WPS都有全局替换的功能(ctrl+h),但是文件过多,且需要替换多次,工作量还是比 ...

  5. javaWeb 字体替换过滤器

    字体替换过滤器继承HttpServletRequestWrapper,重定义了: getParameter(),getParameterValues(),getParameterMap(),增强字节替 ...

  6. android添加第三方字体并设置的简单使用

    1.java文件 package lpc.com.project006; import android.app.Activity; import android.content.res.AssetMa ...

  7. CSS在线字体库,外部字体的引用方法

    目录: 1:CSS家族五大字体 2:360和谷歌外部字体引用方法 3:谷歌外部字体引用方法详解 4:@font-face用法详解 一: {font-family:serif,sans-serif,fa ...

  8. [css] 浏览器字体和css设置字体之间的关系

    原文链接:http://www.zhangxinxu.com/wordpress/2010/06/%E5%8F%AF%E7%94%A8%E6%80%A7%E4%B9%8B%E6%B5%8F%E8%A7 ...

  9. Eclipse3.7默认字体修改-找回Courser-New字体

    1.找到jFace并用WinRAR打开之: jFace的具体位置:$Eclipse目录$/plugins/org.eclipse.jface_3.7.0.I20110522-1430.jar,找到后, ...

随机推荐

  1. BZOJ 4582: [Usaco2016 Open]Diamond Collector

    Descrirption 给你一个长度为 \(n\) 的序列,求将它分成两个序列后最多个数,每个序列最大值最小值不能超过 \(k\) Sol 二分+DP. 排一下序,找出以这个点结尾和开始的位置. 这 ...

  2. 上个项目的一些反思 II

    上个项目需要使用通讯录,我在回顾自己设计的时候,发现自己少设计了cache这一环. 虽然直接用SQLite在初期体验上没什么大损失,不过可以预想通讯录增长到一定数量后势必会影响体验. 单例模式,全局缓 ...

  3. debug [LTS]

    0613 A. 复制代码的时候忘了后续的对称的修改. 统计答案时出现了一些不可理喻的低级失误. B. 在0-indexed的程序中访问第一个元素使用了Arr[1]. Matrix-tree为mat[d ...

  4. 解决Can't connect to MySQL server on 'localhost' (10048)

    解决Can't connect to MySQL server on 'localhost' (10048) 您使用的是Windows操作系统,此错误与一个注册表键值TcpTimedWaitDelay ...

  5. WCF service 获取 client 端的 IP 和 port (转)

    转帖记录一下,以便日后使用. 主要使用是.NET3.5里的服务端上下文的消息实例的RemoteEndpointMessageProperty属性,获取客户端地址信息.但是限制 的绑定是HTTP.TCP ...

  6. WCF

    --http://www.doc88.com/p-699300196010.html ---术语 WCF术语 消息(message) 消息是一个独立的数据单元,它可能由几个部分组成,包括消息正文和消息 ...

  7. 链表原地反转Demo

    现在就是Qt开发和给师弟师妹讲下数据结构吧,感觉还挺漫长的,上个Qt帖子等我把成品做出来再更. //Convert_plug.h #ifndef CONVERT #define CONVERT #de ...

  8. jquery 键盘回车事件

    <input id="search" placeholder="输入要领用的资产条码" id="scanCode" type=&quo ...

  9. 懵逼的闭包--for循环(转)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. [MongoDB]安装MongoDB

    汇总: 1. [MongoDB]安装MongoDB2. [MongoDB]Mongo基本使用:3. [MongoDB]MongoDB的优缺点及与关系型数据库的比较4. [MongoDB]MongoDB ...