iOS设置字体有两种方式
- 是导入我们的字体到工程,调用[UIFont fontWithName:fontName size:size]使用我们的自定义字体;
- 是替换系统设置字体的方法systemFontOfSize、boldSystemFontOfSize等,调用方式就不变。
第二种方式比较灵活,更换字体改动较少。
本文就说说第二种方式。
一、新建UIFont的扩展
@interface UIFont (UIFont_Extension)
@end
@implementation UIFont (UIFont_Extension)
+ (void)setFontName:(NSString *)fontName {
objc_setAssociatedObject(self, @"fontName_", fontName, OBJC_ASSOCIATION_COPY);
}
+ (NSString *)fontName {
return objc_getAssociatedObject(self, @"fontName_");
}
+ (UIFont *) replacement_systemFontOfSize:(CGFloat)fontSize {
return [UIFont fontWithName:self.fontName size:fontSize];
}
+ (UIFont *) replacement_boldSystemFontOfSize:(CGFloat)fontSize {
return [UIFont fontWithName:self.fontName size:fontSize];
}
+ (UIFont *) replacement_italicSystemFontOfSize:(CGFloat)fontSize {
return [UIFont fontWithName:self.fontName size:fontSize];
}
@end
二、新建替换字体的类UIFontExchange
1). 交换系统定义方法与自定义方法的实现
- (void) replacement_systemFont {
//交换systemFontOfSize方法
Method systemFontOfSize_ = class_getClassMethod([UIFont class], @selector(systemFontOfSize:));
Method replacementSystemFontOfSize_ = class_getClassMethod([UIFont class], @selector(replacement_systemFontOfSize:));
if (systemFontOfSize_ && replacementSystemFontOfSize_
&& strcmp(method_getTypeEncoding(systemFontOfSize_), method_getTypeEncoding(replacementSystemFontOfSize_)) == 0)
method_exchangeImplementations(systemFontOfSize_, replacementSystemFontOfSize_);
//交换boldSystemFontOfSize方法
Method boldSystemFontOfSize_ = class_getClassMethod([UIFont class], @selector(boldSystemFontOfSize:));
Method replacementBoldSystemFontOfSize_ = class_getClassMethod([UIFont class], @selector(replacement_boldSystemFontOfSize:));
if (boldSystemFontOfSize_ && replacementBoldSystemFontOfSize_
&& strcmp(method_getTypeEncoding(boldSystemFontOfSize_), method_getTypeEncoding(replacementBoldSystemFontOfSize_)) == 0)
method_exchangeImplementations(boldSystemFontOfSize_, replacementBoldSystemFontOfSize_);
//交换italicSystemFontOfSize方法
Method italicSystemFontOfSize_ = class_getClassMethod([UIFont class], @selector(italicSystemFontOfSize:));
Method replacementItalicSystemFontOfSize_ = class_getClassMethod([UIFont class], @selector(replacement_italicSystemFontOfSize:));
if (italicSystemFontOfSize_ && replacementItalicSystemFontOfSize_
&& strcmp(method_getTypeEncoding(italicSystemFontOfSize_), method_getTypeEncoding(replacementItalicSystemFontOfSize_)) == 0)
method_exchangeImplementations(italicSystemFontOfSize_, replacementItalicSystemFontOfSize_);
}
解析
- class_getClassMethod得到类的类方法,得到UIFont的类方法systemFontOfSize,和UIFont扩展中的类方法replacement_systemFontOfSize。
- method_getTypeEncoding得到systemFontOfSize方法的参数和返回值组成的字符串
NSLog(@"%s", method_getTypeEncoding(systemFontOfSize_));
控制台输出:@24@0:8d16
看着方法声明解释
+(UIFont *)systemFontOfSize:(CGFloat)fontSize;- @ 表示返回一个objective-c的对象
- 24 表示整个方法参数占位的总长度(24bytes)
- @0 在offset为0的地方有一个objective-c的对象,在objective-c method里,首个对象是自身self
- :8 在offset为8的地方有一个SEL
- d16 在offset 16的地方有一个double类型的参数
- strcmp C库函数int strcmp(const char *str1, const char *str2),字符串比较,返回0则这两个地址指向的字符串是一样的。
- method_exchangeImplementations 交换两个方法的实现,也就是交换IMP指针
三、根据字体文件路径获取字体
对于TTF、OTF的字体都有效,但是对于TTC字体,只取出了一种字体。
- (UIFont *)fontWithPath:(NSString*)path size:(CGFloat)size {
NSURL *fontUrl = [NSURL fileURLWithPath:path];
CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)fontUrl);
CGFontRef fontRef = CGFontCreateWithDataProvider(fontDataProvider);
CGDataProviderRelease(fontDataProvider);
CTFontManagerRegisterGraphicsFont(fontRef, NULL);
NSString *fontName = CFBridgingRelease(CGFontCopyPostScriptName(fontRef));
UIFont *font = [UIFont fontWithName:fontName size:size];
CGFontRelease(fontRef);
return font;
}
设置字体
- (void) setFontName:(NSString *)fontName {
NSString *filePath = [[NSBundle mainBundle] pathForResource:fontName ofType:nil];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSString *fontStr = [self fontWithPath:filePath size:14.0].fontName;
[UIFont setFontName:fontStr];
[NSUserDefaults setSettingValue:fontName type:SettingTypeFontFamily];
}
else {
//默认设置的是苹方
[UIFont setFontName:@"PingFangSC-Regular"];
}
}
我做的是在UIFontExchange类的load方法里初始化一个实例调用交换方法和[self setFontName:YourfontName]的。