iOS中利用 runtime 一键改变字体
1、准备
我们新建一个项目名叫ChangeFont,然后我就随便找了个名叫loveway.ttf的字体库拖进去,里面的工程目录大概就是这样的
目录
现在我们就简单的直接在storyboard上拖了一个label一个button,约束好,像这样
storyboard
嗯,就这样,很简单,运行
运行结果
好的显示正常,没什么问题,接下来改变字体。
2、改变字体
我们之前已经把loveway.ttf这个文件拖进去了,现在在plist文件里面配置一下。打开plist然后加入名为Fonts provided by application的一行,在item里把我们的字体名字加进去
plist
最后我们需要保证我们确确实实是加进来了
phases
这个时候也许你已经迫不及待了,赶紧改字体,如下
//
// 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,代码改成这样
- (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,不管了,先试试看行不行

- (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这个方法后面会说,或者不懂得童鞋可以先查查资料),代码如下
//
// 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
然后不加任何代码如下
//
// 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、上面代码中注释了一行
// 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一下吧,谢谢!
iOS中利用 runtime 一键改变字体的更多相关文章
- 【iOS】利用Runtime特性做监控
最近在看Object-C运行时特性,其中有一个特别好用的特性叫 Method Swizzling ,可以动态交换函数地址,在应用程序加载的时候,通过运行时特性互换两个函数的地址,不改变原有代码而改变原 ...
- iOS中利用CoreTelephony获取用户当前网络状态(判断2G,3G,4G)
前言: 在项目开发当中,往往需要利用网络.而用户的网络环境也需要我们开发者去注意,根据不同的网络状态作相应的优化,以提升用户体验. 但通常我们只会判断用户是在WIFI还是移动数据,而实际上,移动数据也 ...
- iOS中动态计算不同颜色、字体的文字高度
在改项目bug的时候,有一个问题动态计算label的高度,前开发者竟然用字符串长度除以14.16这样的常量来计算是否换行,结果cell的高度问题非常严重. 因为label内容里有部分关键字是要另一种颜 ...
- iOS之利用runtime,避免可变数组和可变字典为nil或者数组越界导致的崩溃
NSArray.NSMutableArray.NSDictionary.NSMutableDictionary.是我们的在iOS开发中非常常用的类.当然,在享受这些类的便利的同时,它们也给我们带来一些 ...
- iOS中利用CoreTelephony获取用户当前网络状态(判断2G,3G,4G) by徐文棋
前言: 在项目开发当中,往往需要利用网络.而用户的网络环境也需要我们开发者去注意,根据不同的网络状态作相应的优化,以提升用户体验. 但通常我们只会判断用户是在WIFI还是移动数据,而实际上,移动数据也 ...
- IOS中利用宏将RGB值转换为UIColor(转)
可以在pch文件中定义宏,这样整个项目就都可以用了! #define UIColorFromRGBValue(rgbValue) [UIColor colorWithRed:((float)((rgb ...
- ios中利用NSDateComponents、NSDate、NSCalendar判断当前时间是否在一天的某个时间段内。
应用中设置一般会存在这样的设置,如夜间勿扰模式,从8:00-23:00,此时如何判断当前时间是否在该时间段内.难点主要在于如何用NSDate生成一个8:00的时间和23:00的时间,然后用当前的时间跟 ...
- iOS中利用UISearchBar实现搜索
先把源码贴出来 https://github.com/losedMemory/ZSSearchBar 这是我在github上写的一个Demo,大家可以看看 在大多数app中都会用到搜索功能,那么搜 ...
- 【原创】利用typeface实现不同字体的调用显示及String转换为Unicode
最近工作用到,就写个小demo demo实现从assets中利用typeface调用不同字体,并在editText中显示出来 1.layout中创建activity_main.xml文件 布局代码如下 ...
随机推荐
- Objective-c Category(类别)
NSStringUtilities.h: #import <Foundation/Foundation.h> @interface NSString(Utilities) -(BOOL) ...
- poj2286The Rotation Game(迭代加深dfs)
链接 把迭代加深理解错了 自己写了半天也没写对 所谓迭代加深,就是在深度无上限的情况下,先预估一个深度(尽量小)进行搜索,如果没有找到解,再逐步放大深度搜索.这种方法虽然会导致重复的遍历 某些结点,但 ...
- 关于“javax.servlet.include.request_uri”属性值
在springMVC的DispatcherServlet类的doService方法中有如下代码: if (WebUtils.isIncludeRequest(request)) { attribute ...
- LFS 中文版手册发布:如何打造自己的 Linux 发行版
您是否想过打造您自己的 Linux 发行版?每个 Linux 用户在他们使用 Linux 的过程中都想过做一个他们自己的发行版,至少一次.我也不例外,作为一个 Linux 菜鸟,我也考虑过开发一个自己 ...
- iOS开发中自定义字体的方法
http://www.cnblogs.com/iyou/archive/2014/05/25/3751669.html 1. 首先下载你想要设置的字体库,例如设置方正启体简体 2. 添加到工程,一定要 ...
- FZU 2225 小茗的魔法阵 扫描线+树状数组
这个题和一个CF上的找"Z"的题差不多,都是扫描线+树状数组 从右上角的主对角线开始扫描,一直扫到左下角,每次更新,右延伸等于该扫描线的点,注意在其所在的树状数组更新就好了 时间复 ...
- HDU5647 DZY Loves Connecting 树形DP
(先奉上jcvb大神的官方题解)BC 76 div 1 1002 对于每个结点i,统计出f[i]表示包含i的连通集有多少个,那么容易看出答案就是所有f[i]的和. 要计算f[i]是经典的树形DP问题. ...
- EF RepositoryBase 参考示例【转】
1.定义泛型类 namespace Crm.Data.Logic.Repository{ public abstract class AbstractRepository<TC, T> ...
- Android ListView 全面优化
结合昨天学习的多线程,今天又继续对ListView进行了优化,包括异步加载图片,滑动时暂停加载,滑动停止后再加载显示界面中的item. 综合ListView在使用时参考的多篇博客,这里对ListVie ...
- Docker系列(一)安装
操作系统版本:Centos7 Docker版本:1.8 设置安装源 1 cat > /etc/yum.repos.d/docker.repo << -EOF 2 [dockerr ...