文档章节

iOS中利用 runtime 一键改变字体

 北方人在上海
发布于 2016/05/16 14:30
字数 2079
阅读 18
收藏 1
点赞 2
评论 0

1、准备

我们新建一个项目名叫ChangeFont,然后我就随便找了个名叫loveway.ttf的字体库拖进去,里面的工程目录大概就是这样的

571495-91a43c0fac5f91e4.jpg

目录

现在我们就简单的直接在storyboard上拖了一个label一个button,约束好,像这样

571495-d567ca72aadb692b.jpg

storyboard

嗯,就这样,很简单,运行

571495-e81ac83f048a9545.jpg

运行结果

好的显示正常,没什么问题,接下来改变字体。

2、改变字体

我们之前已经把loveway.ttf这个文件拖进去了,现在在plist文件里面配置一下。打开plist然后加入名为Fonts provided by application的一行,在item里把我们的字体名字加进去

571495-f3a34a72dd21beaa.jpg

plist

最后我们需要保证我们确确实实是加进来了

571495-89647ae861ac1ba8.jpg

phases

这个时候也许你已经迫不及待了,赶紧改字体,如下

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

//

//  ViewController.m

//  ChangeFont

//

#import "ViewController.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UILabel *myLabel;

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    _myLabel.font = [UIFont fontWithName:@"loveway.ttf" size:17.0f];

    _myButton.titleLabel.font = [UIFont fontWithName:@"loveway" size:17.0f];

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end

运行。。。oh no !怎么没变,还是原来的样子?!

肯定是姿势不对,于是百度了一下(虽然我一般都用谷歌),的确这种方法不对。

于是改变思路,先找出字体的名字,Like this,代码改成这样

1

2

3

4

5

6

7

8

9

10

11

- (void)viewDidLoad {

    [super viewDidLoad];

    for(NSString *familyName in [UIFont familyNames]){

        NSLog(@"Font FamilyName = %@",familyName); //*输出字体族科名字

        for(NSString *fontName in [UIFont fontNamesForFamilyName:familyName]) {

            NSLog(@"\t%@",fontName);         //*输出字体族科下字样名字

        }

    }

    _myLabel.font = [UIFont fontWithName:@"loveway.ttf" size:17.0f];

    _myButton.titleLabel.font = [UIFont fontWithName:@"loveway" size:17.0f];

}

运行一看控制台

571495-0aa0ce498e8e115f.jpg

输出的字体名称部分截图

这什么鬼,我哪知道我刚加进去的字体名称是什么,这咋找

于是想出来个办法,再建一个工程,不加入loveway.ttf这个字体,打印出来,一个个对比,多的那个不就是了吗!bingo,于是花了一会功夫终于找出来了,是FZLBJW--GB1-0,不管了,先试试看行不行

1

2

3

4

5

6

7

8

9

10

11

12

13

14

![](http://upload-images.jianshu.io/upload_images/571495-b0d97825e5d33a8a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

- (void)viewDidLoad {

    [super viewDidLoad];

    /*

    for(NSString *familyName in [UIFont familyNames]){

        NSLog(@"Font FamilyName = %@",familyName); //输出字体族科名字

        for(NSString *fontName in [UIFont fontNamesForFamilyName:familyName]) {

            NSLog(@"\t%@",fontName);         //输出字体族科下字样名字

        }

    }

     */

    _myLabel.font = [UIFont fontWithName:@"FZLBJW--GB1-0" size:17.0f];

    _myButton.titleLabel.font = [UIFont fontWithName:@"FZLBJW--GB1-0" size:17.0f];

}

运行,结果如下

571495-c438612edb9e919e.png

改变字体后的运行结果

OK!达到效果了,虽然有点挫,但是效果达到了,还不错。

到这里,基本的改变字体效果已达到。

3、查找字体的一种简单的方法

在上面我们可以看到,通过对比的方法找到了FZLBJW--GB1-0这个名字,这里,有一种简单的方法,我们在 Finder 里面找到这个ttf,双击打开(在Xcode里面双击打开没效果),这时候系统就会用苹果自带的字体册打开,如下:

571495-6f429dd17e7f8a8e.jpg

使用字体册打开.rtf

这样我们就可以看到了这个字体的族科名字,我们看到的是FZLiBian-S02S,于是我们在刚才输出全部字体名的控制台搜索一下这个族科名,就可以知道具体的字体名了

571495-71dbd7f8d809bef6.jpg

搜索FZLiBian-S02S

这样就比上面简单多了。

4、进一步的思考

上面例子中简单的说了一下改变字体的方法,虽然成功了,但是我们不得不思考一下。上面只是两个简单的控件,那么我要是有一堆控件怎么办?或者你可以说我也可用这种方法一个个加,你要是纯代码写的还好,你要是xib写的,难道还要把一个个无用的只是显示一下的label或者button拉出来这样写吗?这样的话,效率肯定会非常低,尤其是那些写到一半的大工程,感觉这种方法肯定是行不通的。

这里利用runtime的class_addMethod、class_replaceMethod、method_exchangeImplementations这几个方法,然后根据+ (void)load这个方法的特性实现(关于+ (void)load这个方法后面会说,或者不懂得童鞋可以先查查资料),代码如下

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

//

//  UILabel+FontChange.m

//  LiquoriceDoctorProject

//

//  Created by HenryCheng on 15/12/7.

//  Copyright ? 2015 iMac. All rights reserved.

//

#import "UILabel+FontChange.h"

#import #define CustomFontName @"FZLBJW--GB1-0"

@implementation UILabel (FontChange)

+ (void)load {

    //方法交换应该被保证,在程序中只会执行一次

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        //获得viewController的生命周期方法的selector

        SEL systemSel = @selector(willMoveToSuperview:);

        //自己实现的将要被交换的方法的selector

        SEL swizzSel = @selector(myWillMoveToSuperview:);

        //两个方法的Method

        Method systemMethod = class_getInstanceMethod([self class], systemSel);

        Method swizzMethod = class_getInstanceMethod([self class], swizzSel);

        //首先动态添加方法,实现是被交换的方法,返回值表示添加成功还是失败

        BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzMethod), method_getTypeEncoding(swizzMethod));

        if (isAdd) {

            //如果成功,说明类中不存在这个方法的实现

            //将被交换方法的实现替换到这个并不存在的实现

            class_replaceMethod(self, swizzSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));

        else {

            //否则,交换两个方法的实现

            method_exchangeImplementations(systemMethod, swizzMethod);

        }

    });

}

- (void)myWillMoveToSuperview:(UIView *)newSuperview {

    [self myWillMoveToSuperview:newSuperview];

//    if ([self isKindOfClass:NSClassFromString(@"UIButtonLabel")]) {

//        return;

//    }

    if (self) {

        if (self.tag == 10086) {

            self.font = [UIFont systemFontOfSize:self.font.pointSize];

        else {

            if ([UIFont fontNamesForFamilyName:CustomFontName])

                self.font  = [UIFont fontWithName:CustomFontName size:self.font.pointSize];

        }

    }

}

@end

然后不加任何代码如下

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

//

//  ViewController.m

//  ChangeFont

//

//  Created by HenryCheng on 16/4/27.

//  Copyright 2016 HenryCheng. All rights reserved.

//

#import "ViewController.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UILabel *myLabel;

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

//    for(NSString *familyName in [UIFont familyNames]){

//        NSLog(@"Font FamilyName = %@",familyName); //输出字体族科名字

//

//        for(NSString *fontName in [UIFont fontNamesForFamilyName:familyName]) {

//            NSLog(@"\t%@",fontName);         //输出字体族科下字样名字

//        }

//    }

//    _myLabel.font = [UIFont fontWithName:@"FZLBJW--GB1-0" size:17.0f];

//    _myButton.titleLabel.font = [UIFont fontWithName:@"FZLBJW--GB1-0" size:17.0f];

//    _myLabel.tag = 10086;

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end

运行

571495-c438612edb9e919e (1).png

我们可以看到字体改变了。

如果有人说我有的想改变字体有的不想改变字体怎么办,我这里有个简单的办法就是设置tag,比如我设置label的tag为10086(随便起的),就让他字体不改变

1462338192307160.png

运行结果

571495-67c22bdfcd9f68b9.png

注意:

1、如果你是代码写控件,你不想改变字体,你只需在创建的时候设置tag为10086

2、上面代码中注释了一行

1

2

3

//if ([self isKindOfClass:NSClassFromString(@"UIButtonLabel")]) {

//      return;

// }

这个是当时写的时候不改变button的title字体设置的,在这里你可以判断那种类型的改哪种不改,比如说你不想改button的字体,把这一句解注释即可

3、如果你是xib拉的控件,你不想改变字体,你必须在xib界面设置tag为10086,不可加载完毕后在- (void)viewDidLoad里面设置,这还是因为+ (void)load这个方法

在一个程序(main函数)运行之前,所用到的库被加载到runtime之后,被添加到的runtime系统的各种类和category的+load方法就被调用;(关于这点很容易通过打印语句来验证);

如果父类和子类的+load方法都被调用,父类的调用一定在子类之前,这是系统自动完成的,子类+load中没必要显式调用[super load];;

这里只是简单的说一下,具体不理解的可以翻翻官方文档

5、最后

关于代码的解释,在工程里都已经注释的非常清楚了,这里就不多说了,不清楚的童鞋可以给我留言。具体用法很简单,你只需要将UILabel+FontChange.h和UILabel+FontChange.m拉进你的工程即可。

需要下载更多字体的可以在字体库下载,所有的代码都可以在这里下载。

最近在看swift,做了一下笔记,后面会为大家分享总结的一些swift tips。

最后,如果你有什么建议或者指正的地方请给我留言,如果喜欢或者对你有帮助的话,就请star一下吧,谢谢!

© 著作权归作者所有

共有 人打赏支持
粉丝 22
博文 187
码字总数 265578
作品 0
浦东
iOS逆向工程- 学习整理(工具详解)

前言 一、逆向工程的要求 具备丰富的 iOS 开发经验 最好能非常熟悉 iOS 设备的硬件构成,iOS 系统的运行原理。 拿到任意一个 App 之后能够大致推断出它的项目规模和使用的技术,比如它的MVC模...

_小迷糊 ⋅ 05/11 ⋅ 0

常见的移动端H5页面开发遇到的坑和解决办法

手机共通问题 问题一:用同等比例的图片在PC机上很清楚,但是手机上很模糊,原因是什么呢? 经研究发现是devicePixelRatio作怪,因为手机分辨率太小,如果按照分辨率来显示网页字会非常小,所以苹果...

webmirror ⋅ 05/02 ⋅ 0

iOS高仿QQ侧滑控件、下载框架、动画效果、扫一扫、颜色变化、K线图等源码

iOS精选源码 仿京东"加入购物车"转场动画(http://www.code4app.com/thread-28162-1-1.html) ColorTool(颜色转换)(http://www.code4app.com/thread-29256-1-1.html) Swift 专业版K线(http://w......

sunnyaigd ⋅ 04/17 ⋅ 0

【AR】开始使用Vuforia开发iOS(2)

原 设置iOS开发环境 安装Vuforia iOS SDK 如何安装Vuforia iOS示例 编译并运行Vuforia iOS示例 支持iOS金属 iOS 64位迁移 设置iOS开发环境 适用于iOS的Vuforia引擎目前支持运行iOS 9及更高版...

lichong951 ⋅ 06/11 ⋅ 0

iOS自定义弹出视图、收音机APP、图片涂鸦、加载刷新、文件缓存等源码

iOS精选源码 一款优秀的 聆听夜空FM 源码(http://www.code4app.com/thread-14546-1-1.html) zhPopupController 简单快捷弹出自定义视图(http://www.code4app.com/thread-14861-1-1.html) WHS......

sunnyaigd ⋅ 06/04 ⋅ 0

面试官自述:面向高级开发人员的iOS面试问题

当您准备进行技术性iOS面试时,了解您可能会询问哪些主题以及经验丰富的iOS开发人员期望什么是非常重要的。 这是许多硅谷公司用来衡量iOS候选人资历水平的一系列问题。 这些问题涉及iOS开发的...

菇哒微课 ⋅ 04/26 ⋅ 0

iOS高仿微信、仪表盘、图片标注图片滤镜、高斯模糊、上拉加载、下拉刷新等源码

iOS精选源码 Swift-图片画框标注(http://www.code4app.com/thread-29884-1-1.html) Swift版的上拉加载, 下拉刷新控件(一句话集成, 超级易用)(http://www.code4app.com/thread-29885-1-1.html...

sunnyaigd ⋅ 05/22 ⋅ 0

ZipperDown漏洞来了!微博、陌陌、快手等常用 iOS 应用恐要中招

雷锋网(公众号:雷锋网)消息,5月15日,盘古实验室对外宣布,他们在针对不同客户的 iOS 应用安全审计过程中,发现了一类通用的安全漏洞---ZipperDown漏洞。 10%的iOS应用可能受ZipperDow...

郭佳 ⋅ 05/15 ⋅ 0

如何判断你是合格的高级iOS开发工程师?

前言 随着移动互联网的高速发展泄洪而来,有意学习移动开发的人越来越多了,竞争也是越来越大,需要学习的东西很多。如何才能在激烈的移动开发者竞争中一枝独秀,成为一名真正合格的高级iOS...

_小迷糊 ⋅ 05/26 ⋅ 0

挖掘安卓宝藏,EMUI会让手机进入“量心定制”时代吗?

如果把移动终端的发展历程看做一部戏剧,那么Android和iOS两种操作系统生态之间的竞争一定是最精彩的一折。 从市场占有率来看,2017年Android手机在全球售出的手机中占据了85.9%份额,其中自...

脑极体 ⋅ 04/17 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

服务网关过滤器

过滤器作用 我们的微服务应用提供的接口就可以通过统一的API网关入口被客户端访问到了。但是,每个客户端用户请求微服务应用提供的接口时,它们的访问权限往往都需要有一定的限制,系统并不会...

明理萝 ⋅ 19分钟前 ⋅ 1

【2018.06.21学习笔记】【linux高级知识 14.1-14.3】

14.1 NFS介绍 NFS服务全称是NetWork File System:网络文件系统,最早有sun公司开发的,4.0版本由Netapp公司开发,是基于RPC远程过程调用(Remote Procedure Call)协议的服务。 14.2 NFS服务...

lgsxp ⋅ 28分钟前 ⋅ 0

Day18 vim编辑模式、命令模式与练习

编辑模式 命令模式 :nohl 不高亮显示 :x与:wq类似,如果在更改文件之后操作,两者效果一样;如果打开文件,没有任何操作; :wq会更改mtime,但是:x不会。 练习题 扩展 vim的特殊用法 ht...

杉下 ⋅ 31分钟前 ⋅ 0

Enum、EnumMap、EnumSet

1、Enum 不带参数 public enum Car { AUDI { @Override public int getPrice() { return 25000; } }, MERCEDES { ......

职业搬砖20年 ⋅ 32分钟前 ⋅ 0

Java中的锁使用与实现

1.Lock接口 锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源。 在Lock出现之前,java程序是靠synchronized关键字实现锁功能的,而Java SE5之后,...

ZH-JSON ⋅ 33分钟前 ⋅ 0

线程组和 ThreadLocal

前言 在上面文章中,我们从源码的角度上解析了一下线程池,并且从其 execute 方法开始把线程池中的相关执行流程过了一遍。那么接下来,我们来看一个新的关于线程的知识点:线程组。 线程组 ...

猴亮屏 ⋅ 34分钟前 ⋅ 0

相对路径和绝对路径

基本概念   文件路径就是文件在电脑中的位置,表示文件路径的方式有两种,相对路径和绝对路径。在网页设计中通过路径可以表示链接,插入图像、Flash、CSS文件的位置。   物理路径:物理路...

临江仙卜算子 ⋅ 38分钟前 ⋅ 0

消息队列属性及常见消息队列介绍

什么是消息队列? 消息队列是在消息的传输过程中保存消息的容器,用于接收消息并以文件的方式存储,一个队列的消息可以同时被多个消息消费者消费。分布式消息服务DMS则是分布式的队列系统,消...

中间件小哥 ⋅ 40分钟前 ⋅ 0

java程序员使用web3j进行以太坊开发详解

如何使用web3j为Java应用或Android App增加以太坊区块链支持,教程内容即涉及以太坊中的核心概念,例如账户管理包括账户的创建、钱包创建、交易转账,交易与状态、智能合约开发与交互、过滤器...

笔阁 ⋅ 41分钟前 ⋅ 0

vim编辑模式、vim命令模式

vim编辑模式 使用vim filename 进入的界面是一般模式,在这个模式下虽然我们能够查看,复制,剪切,粘贴,但是不能编辑新的内容,如何能直接写入东西呢?这就需要进入编辑模式了,从一般模式...

李超小牛子 ⋅ 43分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部