zoukankan      html  css  js  c++  java
  • iOS中利用 runtime 一键改变字体

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

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

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

    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
    //
    //  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(@" %@",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(@" %@",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
    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(@" %@",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一下吧,谢谢!

  • 相关阅读:
    JMS03061AH002 verilog 驱动程序
    modelsim do.do
    Nodemcu的GPIO接口介绍(ZT)
    对于RFIDRC522 模块的读写操作【Arduino】(ZT)
    归并排序
    WebGIS开发培训(ArcGIS API for JavaScript方向)
    将 ASP.NET MVC 2 项目升级到 ASP.NET MVC 3
    控制台应用项目中使用WatinWeb测试工具遇到的问题
    使用UI测试工具Watin遇到的问题(续)
    使用Specflow 和XUnit 进行BDD测试项目配置方法
  • 原文地址:https://www.cnblogs.com/itlover2013/p/5476400.html
Copyright © 2011-2022 走看看