矢量图标管理
背景
基于图片的图标管理
项目中原有的图标是以.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设计,工作量太大。因此需考虑向前兼容性。
实现
矢量图标生成和设置
- UX使用Sketch等工具生成图标的svg格式的矢量图,然后使用http://fontello.com/ 等工具生成.ttf格式的字体文件
- 将文件放入Resource文件夹下,例如将IconFont.ttf文件放在/Resource/Icon/文件夹下
- 在target的 BuildPhases->Copy Build Resources->中,添加/Resource/Icon/ 文件夹即可。
矢量图标的使用
- 自定义的工具类MSIVectorIconHelper提供了一个方法,生成NSAttributedString
|
|
- 使用
|
|
向前兼容性
提供根据矢量图生成指定大小的UIImage供原有代码使用。
|
|
实现核心
- 首先生成一个256*256大小的UILabel(vectorIcon),根据具体的iconName, 二分查找出尽可能布满Label的最小字号,用drawTextInRect:完成绘制
然后使用 grabImage 生成其对应的Image:
1234567891011+ (UIImage *)grabImage:(UIView *)view {// create a "canvas" (image context) to draw inUIGraphicsBeginImageContextWithOptions([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 inputUIGraphicsEndImageContext();return image;}最后使用imageScaledToSize放缩图像到指定的大小:
12345678910- (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以提高性能。