iOS字体适配

最近项目中,UI要求字体适配屏幕,根据屏幕大小来决定字体大小,因为在大屏手机上字体确实显得小了。因为之前没做过,所以今天抽空研究了一下,还是有一些值得记录的内容

  1. 通过代码设置的字体适配
    代码设置字体,因为已经写过很多地方,不可能一个一个的改,所以使用了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;
    }
    
  2. 通过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两个分类

  3. 遇到的问题及解决
    因为之前写的都是交换实例方法,没写过类方法的交换,所以我直接按着实例方法来写,发现交换不了

    + (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);
        }
    }
    
  4. 参考链接

原文地址:https://www.cnblogs.com/shenyuiOS/p/14232014.html