使用分类通过runtime使用方法替换功能
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (Category)
/**
@brief 方法替换
@param originselector 替换的原方法
@param swizzleSelector 替换后的方法
@param isClassMethod 是否为类方法,YES为类方法,NO为对象方法
*/
+ (void)runtimeReplaceFunctionWithSelector:(SEL)originselector
swizzleSelector:(SEL)swizzleSelector
isClassMethod:(BOOL)isClassMethod;
@end
NS_ASSUME_NONNULL_END
#import "NSObject+Category.h"
#import <objc/runtime.h>
@implementation NSObject (Category)
/**
@brief 方法替换
@param originselector 替换的原方法
@param swizzleSelector 替换后的方法
@param isClassMethod 是否为类方法,YES为类方法,NO为对象方法
*/
+ (void)runtimeReplaceFunctionWithSelector:(SEL)originselector
swizzleSelector:(SEL)swizzleSelector
isClassMethod:(BOOL)isClassMethod
{
Method originMethod;
Method swizzleMethod;
if (isClassMethod == YES) {
originMethod = class_getClassMethod([self class], originselector);
swizzleMethod = class_getClassMethod([self class], swizzleSelector);
}else{
originMethod = class_getInstanceMethod([self class], originselector);
swizzleMethod = class_getInstanceMethod([self class], swizzleSelector);
}
method_exchangeImplementations(originMethod, swizzleMethod);
}
@end
针对UIFont UIlabel UIButton UITextView UITextField 写分类
#import "UIFont+Category.h"
#import "NSObject+Category.h"
@implementation UIFont (Category)
//+(void)load方法会在main函数之前自动调用,不需要手动调用
+ (void)load
{
//交换systemFontOfSize: 方法
[[self class] runtimeReplaceFunctionWithSelector:@selector(systemFontOfSize:) swizzleSelector:@selector(customSystemFontOfSize:) isClassMethod:YES];
//交换fontWithName:size:方法
[[self class] runtimeReplaceFunctionWithSelector:@selector(fontWithName:size:) swizzleSelector:@selector(customFontWithName:size:) isClassMethod:YES];
//交换systemFontOfSize:weight:方法
[[self class] runtimeReplaceFunctionWithSelector:@selector(systemFontOfSize:weight:) swizzleSelector:@selector(customSystemWeightFontOfSize:weight:) isClassMethod:YES];
}
//自定义的交换方法
+ (UIFont *)customSystemFontOfSize:(CGFloat)fontSize
{
CGFloat size = [UIFont transSizeWithFontSize:fontSize];
///这里并不会引起递归,方法交换后,此时调用customSystemFontOfSize方法,其实是调用了原来的systemFontOfSize方法
return [UIFont customSystemFontOfSize:size];
}
//自定义的交换方法
+ (UIFont *)customSystemWeightFontOfSize:(CGFloat)fontSize weight:(UIFontWeight)weightName
{
CGFloat size = [UIFont transSizeWithFontSize:fontSize];
///这里并不会引起递归,方法交换后,此时调用customSystemFontOfSize方法,其实是调用了原来的systemFontOfSize方法
return [UIFont customSystemWeightFontOfSize:size weight:weightName];
}
//自定义的交换方法
+ (UIFont *)customFontWithName:(NSString *)fontName size:(CGFloat)fontSize
{
CGFloat size = [UIFont transSizeWithFontSize:fontSize];
return [UIFont customFontWithName:fontName size:size];
}
/// 根据设置的大 中 小 对原有字体大小进行处理
+ (CGFloat)transSizeWithFontSize:(CGFloat)fontSize
{
CGFloat size = fontSize;
NSString *sizeFont = [kMyUserDefult objectForKey:@"setSizeFontData"];
if ([sizeFont isEqualToString:@"大"]) {
size += 2;
}else if ([sizeFont isEqualToString:@"小"]){
size -= 2;
}
return size;
}
@end
#import "UILabel+Category.h"
#import "NSObject+Category.h"
@implementation UILabel (Category)
+ (void)load
{
[[self class] runtimeReplaceFunctionWithSelector:@selector(initWithCoder:) swizzleSelector:@selector(customInitWithCoder:) isClassMethod:NO];
}
- (instancetype)customInitWithCoder:(NSCoder *)coder
{
if ([self customInitWithCoder:coder]) {
///此时调用fontWithName:size:方法,实际上调用的是方法交换后的customFontWithName:size:
self.font = [UIFont fontWithName:self.font.familyName size:self.font.pointSize];
}
return self;
}
@end
#import "UIButton+Category.h"
#import "NSObject+Category.h"
@implementation UIButton (Category)
+ (void)load
{
[[self class] runtimeReplaceFunctionWithSelector:@selector(initWithCoder:) swizzleSelector:@selector(customInitWithCoder:) isClassMethod:NO];
}
- (instancetype)customInitWithCoder:(NSCoder *)coder
{
if ([self customInitWithCoder:coder]) {
if (self.titleLabel != nil) {
self.titleLabel.font = [UIFont fontWithName:self.titleLabel.font.familyName size:self.titleLabel.font.pointSize];
}
}
return self;
}
@end
#import "UITextField+Category.h"
#import "NSObject+Category.h"
@implementation UITextField (Category)
+ (void)load
{
[[self class] runtimeReplaceFunctionWithSelector:@selector(initWithCoder:) swizzleSelector:@selector(customInitWithCoder:) isClassMethod:NO];
}
- (instancetype)customInitWithCoder:(NSCoder *)coder
{
if ([self customInitWithCoder:coder]) {
self.font = [UIFont fontWithName:self.font.familyName size:self.font.pointSize];
}
return self;
}
@end
#import "UITextView+Category.h"
#import "NSObject+Category.h"
@implementation UITextView (Category)
+ (void)load
{
[[self class] runtimeReplaceFunctionWithSelector:@selector(initWithCoder:) swizzleSelector:@selector(customInitWithCoder:) isClassMethod:NO];
}
- (instancetype)customInitWithCoder:(NSCoder *)coder
{
if ([self customInitWithCoder:coder]) {
self.font = [UIFont fontWithName:self.font.familyName size:self.font.pointSize];
}
return self;
}
@end
打开APP 会根据设置的大中小进行处理字体。
如果需要根据设置界面设置大中小进行改变的话,需要在一级界面注册相同的通知,在设置界面改变大中小后发送通知
[kMyUserDefult setObject:sizeFont forKey:@"setSizeFontData"];
[[NSNotificationCenter defaultCenter] postNotificationName:REFRESH_SIZEFONT_DATA object:nil];
[tableView reloadData];
在所有的一级界面接收到通知的方法需要刷新整个界面,如果是列表可以直接刷新,如果不是列表 需要刷新指定view的font ,不是一级界面不需要刷新font,因为进入不是一级界面会走分类的+load方法,会走方法替换功能
一级界面如果是xib 把指定的 UIlabel UIButton UITextView UITextField 线拉出来,设置font,到时候刷新的话可以重新刷新到,进行改变font的值。
设置界面修改大中小字体时,一级界面和设置大中小界面 需要刷新view 让他重新走设置font值,其他都不用动,其他界面会走+load方法