iOS中利用 runtime 一键改变字体

http://www.cocoachina.com/ios/20160504/16109.html

本文为投稿文章,作者:HenryCheng(简书

最近公司要在5月份举办个大型的发布会,所以在这之前要把版本稳定,界面提升,所以有很多细活要干。不过,趁前两天版本刚提交上线,这两天稍微闲一点,就把之前说的利用runtime一键改变字体的方法分享出来。有人会说,改变字体不是很简单吗,我直接找到字体名替换一下不就好了?客官不要急,先坐下来吃点瓜子,听我慢慢给你说来。

1、准备

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

目录

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

storyboard

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

运行结果

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

2、改变字体

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

plist

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

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

//

//  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];

    _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];

}

运行一看控制台

输出的字体名称部分截图

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

于是想出来个办法,再建一个工程,不加入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];

}

运行,结果如下

改变字体后的运行结果

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

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

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

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

使用字体册打开.rtf

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

搜索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

49

//

//  UILabel+FontChange.m

//  LiquoriceDoctorProject

//

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

//  Copyright ? 2015年 iMac. All rights reserved.

//

#import "UILabel+FontChange.h"

#import <objc runtime.h="">

#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</objc>

然后不加任何代码如下


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

运行

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

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

运行结果

注意:

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一下吧,谢谢!

时间: 2024-11-07 10:33:32

iOS中利用 runtime 一键改变字体的相关文章

IOS中利用NSKeyedArchiver进行数据的归档和恢复

1.相关知识点: <1> 可以利用NSKeyedArchiver 进行归档和恢复的对象类型:NSString .NSDictionary.NSArray.NSData.                        NSNumber等 <2> 使用是必须遵循NSCoding协议对象,实现两个方法: encodeWithCoder:归档对象时,将会调用该方法. initWithCoder:每次从文件中恢复对象时,调用该方法. 2.简单例子阐述详细步骤 <1> 创建一个学生

ios中利用NSDateComponents、NSDate、NSCalendar判断当前时间是否在一天的某个时间段内。

应用中设置一般会存在这样的设置,如夜间勿扰模式,从8:00-23:00,此时如何判断当前时间是否在该时间段内.难点主要在于如何用NSDate生成一个8:00的时间和23:00的时间,然后用当前的时间跟这俩时间作对比就好了. 下面提供两条思路: 法1.用NSDate生成当前时间,然后转为字符串,从字符串中取出当前的年.月.日,然后再拼上时.分.秒,然后再将拼接后的字符串转为NSDate,最后用当前的时间跟自己生成的俩NSDate的时间点比较.(该方法比较笨,也不难,但看起来有点太菜了,看上去不怎么

iOS中通过设置CSS改变WebView字体大小,颜色,背景颜色

因为WebView自带的属性是不可以改变字体大小颜色这些需求的,只能通过改变css样式,内置来解决.在百度上搜了半天很多不靠谱,现在给出几种解决方案如下: 1.第一种方式:在WebView的代理方法webViewDidFinishLoad中: 字体大小: [webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '12

iOS中利用CoreTelephony获取用户当前网络状态(判断2G,3G,4G)

前言: 在项目开发当中,往往需要利用网络.而用户的网络环境也需要我们开发者去注意,根据不同的网络状态作相应的优化,以提升用户体验. 但通常我们只会判断用户是在WIFI还是移动数据,而实际上,移动数据也分为2G/3G/4G等不同制式.而不同的网络制式又对用户体验产生 较为明显的影响(对于依赖网络的项目而言).因此很有必要对不同的网络制式作相应的优化. 而在iOS当中,无论是苹果官方提供的Reachability类还是较为常用的第三方网络类AFNetworking,它们提供的网络环境判断也仅限 于W

我理解的iOS中的RunTime机制(1)

一.首先我们要先知道object-c是一门编译型.动态语言(这里强调下oc是静态类型语言),这在开发语言中是并多见的,一般的动态语言多为解释性语言.oc之所以能够做到即使编译型语言,又是动态语言.就是得益于RunTime机制. 由于本文主要讲解的是RunTime机制,所以语言类型不做过多描述,之后可以另写一篇语言类型的介绍. 二.这里主要讲解RunTime如何使用,其中主要的知识点如下: 1.class_copyPropertyList  获取一份拷贝的成员列表数组 2.property_get

iOS中利用NSURLSession进行文件断点下载

第一部分 知识储备 1.对NSURLSesiion的认识 NSURLSesiion是苹果在iOS7推出的一个类,它具备了NSURLConnection所具备的方法,同时也比它更强大.苹果推出它的目的大有取代NSURLConnection的趋势或者目的. 2.  NSURLSesiion的作用 实现对文件的下载与上传.在NSURLSesiion中,任何请求都可以被看做是一个任务.而NSURLSesiionData 有两个子类:NSURLSessionDownlaodTask实现文件下载和NSURL

iOS UILabel根据文本宽度改变字体大小

之前一直不知道有这样一个属性,看了这篇博文才知道 http://my.oschina.net/joanfen/blog/145184 myLabel.adjustsFontSizeToFitWidth = YES; //假设文字内容为@"曾在月光之下望烟花,曾共看夕阳渐降下",Label长度为200,则一行显示不下,若设置此属性为YES,则会降低字体大小,以显示全部内容.

IOS中利用宏将RGB值转换为UIColor(转)

可以在pch文件中定义宏,这样整个项目就都可以用了! 1 #define UIColorFromRGBValue(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

【原创】利用typeface实现不同字体的调用显示及String转换为Unicode

最近工作用到,就写个小demo demo实现从assets中利用typeface调用不同字体,并在editText中显示出来 1.layout中创建activity_main.xml文件 布局代码如下: 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 andr