最近项目中,UI要求字体适配屏幕,根据屏幕大小来决定字体大小,因为在大屏手机上字体确实显得小了。因为之前没做过,所以今天抽空研究了一下,还是有一些值得记录的内容
-
通过代码设置的字体适配
代码设置字体,因为已经写过很多地方,不可能一个一个的改,所以使用了method swizzle的方法,用自定义方法替换系统设置字体的方法//UIFont+Custom.m + (void)load { static dispatch_once_t fontToken; dispatch_once(&fontToken, ^{ [self exchangeClassMethod:@selector(systemFontOfSize:) withMethod:@selector(adapterSystemFontOfSize:)]; [self exchangeClassMethod:@selector(systemFontOfSize:weight:) withMethod:@selector(adapterSystemFontOfSize:weight:)]; [self exchangeClassMethod:@selector(fontWithName:size:) withMethod:@selector(adapterFontWithName:size:)]; }); } + (UIFont *)adapterSystemFontOfSize:(CGFloat)size { CGFloat adapterSize = [self getAdapterFontSize:size]; return [self adapterSystemFontOfSize:adapterSize]; } + (UIFont *)adapterSystemFontOfSize:(CGFloat)size weight:(UIFontWeight)weight { CGFloat adapterSize = [self getAdapterFontSize:size]; return [self adapterSystemFontOfSize:adapterSize weight:weight]; } + (UIFont *)adapterFontWithName:(NSString *)name size:(CGFloat)size { CGFloat adapterSize = [self getAdapterFontSize:size]; return [self adapterFontWithName:name size:adapterSize]; } //获取适配后的字体大小 + (CGFloat)getAdapterFontSize:(CGFloat)size { CGFloat adapterSize = size; if (IS_NOTCH_SCREEN) { adapterSize = size + 2; } else if (IS_BIG_SCREEN) { adapterSize = size + 1; } else { adapterSize = size; } // NSLog(@"size %f, adapter %f", size, adapterSize); return adapterSize; }
-
通过xib/storyboard设置的字体适配
xib/storyboard里面设置的字体都是固定大小的,想要适配不同的屏幕,可以通过两种方式:1.手动设置字体大小,因为上面我们已经替换了uifont的方法,所以在设置的时候就会适配。2.重写awakefromnib方法,在初始化完成后设置自动字体大小。因为已经写了很多页面,不好一个一个修改,所以这里用第二种方法实现//UILabel+Custom.m + (void)load { static dispatch_once_t fontToken; dispatch_once(&fontToken, ^{ [self exchangeInstanceMethod:@selector(awakeFromNib) withMethod:@selector(awakeFromNibAndSetFont)]; }); } - (void)awakeFromNibAndSetFont { CGFloat adapterSize = [UIFont getAdapterFontSize:self.font.pointSize]; self.font = [UIFont fontWithDescriptor:self.font.fontDescriptor size:adapterSize]; [self awakeFromNibAndSetFont]; }
同理需要对其他的可以设置字体的空间添加分类,替换awakefromnib方法。我这里使用了UILabel和UITextField两个分类
-
遇到的问题及解决
因为之前写的都是交换实例方法,没写过类方法的交换,所以我直接按着实例方法来写,发现交换不了+ (void)exchangeClassMethod:(SEL)originSelector withMethod:(SEL)newSelector { Class class = self; Method originMethod = class_getClassMethod(class, originSelector); Method newMethod = class_getClassMethod(class, newSelector); BOOL addSuccess = class_addMethod(class, originSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); if (addSuccess) { class_replaceMethod(class, newSelector, method_getImplementation(originMethod), method_getTypeEncoding(originMethod)); } else { method_exchangeImplementations(originMethod, newMethod); } }
原来是因为添加方法的时候,添加到了类上,而类方法是在元类里面的,所以导致添加成功但是替换之后没效果。在添加方法的时候改成添加到元类上即可。 因为用到的地方比较多所以对方法替换进行了简单的封装,并添加到NSObject的分类中
//NSObject+Custom.m + (void)exchangeClassMethod:(SEL)originSelector withMethod:(SEL)newSelector { Class class = self; Method originMethod = class_getClassMethod(class, originSelector); Method newMethod = class_getClassMethod(class, newSelector); //类方法需要添加到类对象的父类-元类上 BOOL addSuccess = class_addMethod(object_getClass(class), originSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); if (addSuccess) { class_replaceMethod(class, newSelector, method_getImplementation(originMethod), method_getTypeEncoding(originMethod)); } else { method_exchangeImplementations(originMethod, newMethod); } } + (void)exchangeInstanceMethod:(SEL)originSelector withMethod:(SEL)newSelector { Class class = self; Method originMethod = class_getInstanceMethod(class, originSelector); Method newMethod = class_getInstanceMethod(class, newSelector); BOOL addSuccess = class_addMethod(class, originSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); if (addSuccess) { class_replaceMethod(class, newSelector, method_getImplementation(originMethod), method_getTypeEncoding(originMethod)); } else { method_exchangeImplementations(originMethod, newMethod); } }
-
参考链接