zoukankan      html  css  js  c++  java
  • 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. 参考链接

  • 相关阅读:
    Android UI--自定义ListView(实现下拉刷新+加载更多)
    12306火车票订票网站的一个Bug
    golang中赋值string到array
    Node.js学习(14)----EJS模板引擎
    操作系统
    springMVC学习笔记--初识springMVC
    sqlplus 连接数据库报错SP2-0642: SQL*Plus internal error state 2130, context 0:0:0
    对于事务和同步(并发)的简要理解
    Jsoup入门
    [LeetCode]Single Number
  • 原文地址:https://www.cnblogs.com/shenyuiOS/p/14232014.html
Copyright © 2011-2022 走看看