文章目录
  1. 1. 背景
    1. 1.0.1. 基于图片的图标管理
    2. 1.0.2. 矢量图标管理
  • 2. 实现
    1. 2.0.1. 矢量图标生成和设置
    2. 2.0.2. 矢量图标的使用
    3. 2.0.3. 向前兼容性
  • 3. 其他考虑
  • 背景

    基于图片的图标管理

    项目中原有的图标是以.png图片的形式提供,比如一个箭头图标,就需要提供 arrow.png (20px20px), arrow@2x.png (40px40px), arrow@3x.png (60px*60px) 三张不同分辨率图片,存放在Resource/下的bundle里。既占用空间,又不便于维护和管理。

    矢量图标管理

    优点:

    • 减小app的大小,现有的图标资源文件占整个app大小的大约18%(压缩前约54M, 压缩后约9MB),而对应的Vector Font的资源文件在 300KB~500KB,仅占原有大小的1/50。
    • 方便管理和部署。 只需维护一个.ttf文件而非维护非常多的图片文件;矢量图不失真,支持以后更高分辨率的要求。
    • 跨平台。 还可以提供给Android或者Web等使用。

    潜在的顾虑:

    • 性能下降。(需测试)
    • 需在工程各个地方替换,有一定的工作量
    • 之前的UX设计都是基于图标像素的,而不是字号(fontSize)。如果全部重新给出基于字号的UX设计,工作量太大。因此需考虑向前兼容性。

    实现

    矢量图标生成和设置

    1. UX使用Sketch等工具生成图标的svg格式的矢量图,然后使用http://fontello.com/ 等工具生成.ttf格式的字体文件
    2. 将文件放入Resource文件夹下,例如将IconFont.ttf文件放在/Resource/Icon/文件夹下
    3. 在target的 BuildPhases->Copy Build Resources->中,添加/Resource/Icon/ 文件夹即可。

    矢量图标的使用

    1. 自定义的工具类MSIVectorIconHelper提供了一个方法,生成NSAttributedString
    1
    2
    3
    4
    5
    6
    // Provide vector icon as text. It'll be set in UILabel and used as an icon viewer.
    + (nullable NSAttributedString *)generateIconText:(nonnull NSString *)iconName fontSize:(NSInteger)size color:(nullable UIColor *)color
    {
    //简化版
    return [[NSMutableAttributedString alloc] initWithString:[MSIVectorIcon getUnicode:iconName] attributes:@{[NSFontAttributeName: @"IconFont", NSForegroundColorAttributeName: color]}]; // IconFont即为IconFont.ttf文件名
    }
    1. 使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    NSAttributedString* iconString = [MSIVectorIconHelper generateIconText:@"ra_filter_expand"
    fontSize: fontSize
    color: fontColor];
    iconView = [[UILabel alloc] init];
    iconView.attributedText = iconString;
    CGSize iconSize = iconView.intrinsicContentSize;
    // 或者
    // CGSize iconSize = [iconString boundingRectWithSize:CGSizeMake(INT32_MAX, INT32_MAX)
    options:NSStringDrawingUsesLineFragmentOrigin
    context:nil];
    iconView.frame = CGRectMake(X, XX, iconSize.width, iconSize.height);
    XXX.addSubView(iconView);

    向前兼容性

    提供根据矢量图生成指定大小的UIImage供原有代码使用。

    1
    2
    3
    4
    // Forward compatible, provide UIImage based on vector icon.
    + (nullable UIImage *)generateImage:(nonnull NSString *)iconName;
    + (nullable UIImage *)generateImage:(nonnull NSString *)iconName imageSize:(CGSize)size color:(nullable UIColor *)defaultColor;
    + (nullable UIImage *)generateImage:(nonnull NSString *)iconName colorWithInt:(NSInteger)colorInt alpha:(CGFloat)alpha;

    实现核心

    1. 首先生成一个256*256大小的UILabel(vectorIcon),根据具体的iconName, 二分查找出尽可能布满Label的最小字号,用drawTextInRect:完成绘制
    2. 然后使用 grabImage 生成其对应的Image:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      + (UIImage *)grabImage:(UIView *)view {
      // create a "canvas" (image context) to draw in
      UIGraphicsBeginImageContextWithOptions([view bounds].size, NO, 0.0);
      // Make the CALayer to draw in our "canvas"
      [[view layer] renderInContext:UIGraphicsGetCurrentContext()];
      // Fetch an UIImage of our "canvas"
      UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
      // stop the "canvas" from accepting any input
      UIGraphicsEndImageContext();
      return image;
      }
    3. 最后使用imageScaledToSize放缩图像到指定的大小:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      - (UIImage *)imageScaledToSize:(CGSize)newSize
      {
      // In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
      // Pass 1.0 to force exact pixel size.
      UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
      [self drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
      UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
      return newImage;
      }

    其他考虑

    由于生成UIImage需要一定的时间,因此在工具类MSIVectorIconHelper添加一个NSDictionary作为图片的缓存,可以记录最近的10个UIImage以提高性能。

    文章目录
    1. 1. 背景
      1. 1.0.1. 基于图片的图标管理
      2. 1.0.2. 矢量图标管理
  • 2. 实现
    1. 2.0.1. 矢量图标生成和设置
    2. 2.0.2. 矢量图标的使用
    3. 2.0.3. 向前兼容性
  • 3. 其他考虑