App 中使用 Iconfont 的整套方案


什么是Iconfont

我們通常看到的圖標都是以圖片形式集成到項目中使用,而 Iconfont 是一套字體圖標,和我們使用自定義字體的方式是一樣的,並且它是一種矢量圖標。

計算機中顯示的圖形一般分為兩類---位圖和矢量圖,我們平常使用的JPEG、PNG等圖片都是位圖格式,是一種由像素來表示的圖像,而矢量圖是由點、直線、多邊形等基於數學方程的幾何圖元表示的圖像,對比位圖,矢量圖具有體積小,放大縮小都不會失真的優點,這個優點就可以給項目帶來很大好處了,但缺點是無法用來表達色彩層次豐富的圖像,因此一些色彩復雜的圖形仍然需要位圖去表達。正巧我們項目在進行模塊化,碰到不同模塊使用到相同的圖片時,尤其是這種基礎icon,復制多份到各自的模塊中是不太優雅的,利用Iconfont就可以很好的解決。

優點

  • 縮放不會模糊,告別iOS中2x/3x以及未來nx的問題
  • 一套資源可在web、iOS、Android等多個平台使用
  • 一鍵換膚、方便更改圖片顏色,圖片復用
  • 一定程度上減小包體積
  • 有利於項目模塊化

缺點

  • 圖標制作/更新成本高
  • 只支持單色

如何制作Iconfont

首先,你得擁有一套完美的圖標庫,如下圖,這里我們選用Sketch為容器去維護這些圖標,畢竟對程序員來說是比較容易上手的工具,注意矢量圖的制作還是需要設計師的哦,不然有的是坑讓你踩的。不管使用AI還是其他什么矢量圖繪制軟件制作的圖標我們最終都放入這個文件中,后續的更新也是往后面逐一增加。

 

可以看出來,其實都是一些基礎通用icon,這些icon復用率非常高,如果你們公司有多個App,復用這一個字體文件就可以快速使用圖標而不需要各種拷貝圖片資源了。我們最終需要的是一個包含所有圖標的字體文件即ttf文件,使用過自定義字體的開發者應該都知道ttf(TrueType font),我們在電腦上是可以直接雙擊ttf文件安裝字體使用的。如下圖

那么如何將這些矢量圖標最終合並為一個字體文件呢?

將sketch中的圖標導出

上面說了有矢量圖和位圖之分,那么位圖就是平常我們導出的后綴為png、jpeg、gif這種格式的,矢量圖一般有.ai,.pdf,.svg等等,這里我們導出為svg格式。Bohemian Coding(Sketch的制作團隊)發布過一款名為 SketchTool 的命令行工具,用來自動導出 .sketch 文件當中的界面和切片。如果你願意手動一張張導出也可以,我敬你是條漢子~

安裝好 sketch 后,在命令行中執行如下命令安裝 sketchtool (換成你自己的路徑)

sh /Applications/Sketch.app/Contents/Resources/sketchtool/install.sh

我們通過下面的命令批量導出圖標,其中 ${SRCROOT}/../ZanIconFont/Icon/icons.sketch 替換成你的 iconfont.sketch 的路徑,${SRCROOT}/../ZanIconFont/Icon/svg 替換成你的導出目標路徑

sketchtool export slices ${SRCROOT}/../ZanIconFont/Icon/icons.sketch --output=${SRCROOT}/../ZanIconFont/Icon/svg --formats=svg

export slices :導出切片,這個跟sketch中的設置相關,我們這里每一個圖標設置成了slice,所以對應的命令使用的是 export slices,如果每個圖標都有自己的artboard,那么就是 export artboards。
--format=svg :導出為svg格式。

sketchtool相關的命令以及參數我們都可以通過在命令行中輸入sketchtool來查看,這里就不細說啦。導出的部分svg圖片如下:

合成ttf字體文件

我們需要將上述所有svg圖片合並為一個ttf,這里我們使用的是內部前端組開發的一個命令行工具 iconfount,已經開源,安裝以及詳細說明可以在github上看到。

在命令行中執行

iconfount --found-config.js

其中 found-config.js 是你的配置文件,支持js或者json,在iconfount項目的sample/目錄下有個示例配置文件,可以參考。看下我們的配置文件部分截圖:

name:字體名稱(familyName),就是后續代碼中注冊字體用到的。
output:輸出字體、樣式以及示例文件的目錄,可以是相對路徑或者絕對路徑
glyphs_dir:存放svg文件的根目錄,就是上一步生成的svg目錄。
glyphs:所有圖標的定義,每個圖標都有keywords、src等等若干其他屬性,我們這里只需要使用src屬性即可。最好與項目中每個圖標的name保持一致。

其他的參數在github上都有詳細說明,這里就不一一列舉啦。

最終會生成如下一些文件

 

可以看到在font文件夾中已經包含了ttf,另外還有woff、eot等其他類型,這些都是用於web端的,對於App可以先不用管。我們再看到有個demo.html如下,列舉了圖標列表,點擊右上角show codes可以查看對應的編碼。我們在項目中使用iconfont時是需要依賴這個demo.html的可視化界面的,否則你不知道編碼所對應的圖標是長什么樣子的。

以上是生成ttf字體文件的整個流程,而另外也有很多優秀的平台提供整套功能,例如 Iconfonticomoonfontello 等等,這些平台都提供了很多成熟的圖標集,支持在線導入自定義的SVG圖標,生成樣式、字體文件等等一整套方案,關於這些平台的使用這里不再贅述,各個官網以及很多文章都有很詳細的說明。但是我們考慮到的是后期維護更新還是比較麻煩,如果更新圖標需要重新導入到平台上、生成字體文件、再引入項目,每次需要手動去完成。因此產生了 iconfount,他是基於fontello、使用了很多fontello的代碼和庫而開發一個命令行工具,能夠很好的整合到項目中完成自動化,后續圖標更新了,設計師只要更新圖標本身即可,而我們的Iconfont庫重新build一遍即可完成所有的操作。這里iOS使用了Cocoapods去管理Iconfont私有庫,因此每次更新圖標后Iconfont庫的開發者去更新下sketch整個文件,重新build一遍就會自動去執行導出svg圖標、生成字體文件的腳本,業務方升級一下版本即可。

在iOS中使用

先看下簡單的demo

 

首先把上面制作的ttf字體文件引入到項目中,代碼中注冊字體,打印出來是可以找到你的字體的。

+ (void)registerFontWithURL:(NSURL *)url { NSAssert([[NSFileManager defaultManager] fileExistsAtPath:[url path]], @"Font file doesn't exist"); CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)url); CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider); CGDataProviderRelease(fontDataProvider); CTFontManagerRegisterGraphicsFont(newFont, nil); CGFontRelease(newFont); NSLog(@"%@",[UIFont familyNames]); } 

使用場景:

as text

是字體文件的一般用法,代碼如下。但是這種方式在替換原來的圖標過程中會改變添加控件的方式,原本都是用UIImageView圖片控件而現在要改成UILabel或其他文本控件了,所以這邊我們推薦使用第二種。

label.attributedText = [ZanIconFont attributedStringWithIcon:zicon_edit fontSize:20 color:[UIColor redColor]] 

部分實現

+ (NSAttributedString *)attributedStringWithIcon:(ZanIconName)iconName fontSize:(CGFloat)fontSize color:(UIColor *)color { UIFont *font = [self fontWithSize:fontSize]; NSMutableDictionary *attributed = [NSMutableDictionary dictionaryWithDictionary:@{NSFontAttributeName:font}]; if (color) { [attributed setObject:color forKey:NSForegroundColorAttributeName]; } return [[NSAttributedString alloc] initWithString:iconName attributes:attributed]; } 

as image

我們采用Category的方式對UIImageView增加設置圖片的方法,同時也可以對UIButton、UILabel等其他控件增加Category。這里會去讀取UIImageView控件的bounds作為image的size。

[self.imageView setImageWithIcon:zicon_edit]; 

也可以自定義image的size、fontSize、tintColor等屬性

UIImage *image = [ZanIconFont imageWithIcon:zicon_edit imageSize:CGSizeMake(30, 30) fontSize:20 tintColor:[UIColor redColor]]; 

部分實現

+ (UIImage *)imageWithIcon:(ZanIconName)iconName imageSize:(CGSize)imageSize fontSize:(CGFloat)fontSize tintColor:(UIColor *)tintColor { if (!iconName) { NSAssert(iconName, @"icon object should not be nil, check if the font file is added to the application bundle and you're using the correct font name."); return nil; } UIGraphicsBeginImageContextWithOptions(imageSize, NO, [UIScreen mainScreen].scale); CGContextRef context = UIGraphicsGetCurrentContext(); NSMutableAttributedString *fontString = [ZanIconFont attributedStringWithIcon:iconName fontSize:fontSize color:tintColor]; CGSize iconSize = [fontString size] ; CGFloat xOffset = (imageSize.width - iconSize.width) / 2.0; CGFloat yOffset = (imageSize.height - iconSize.height) / 2.0; CGRect rect = CGRectMake(xOffset, yOffset, iconSize.width, iconSize.height); [fontString drawInRect:rect]; UIImage *iconImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return iconImage; } 

也支持在Storyboard上設置icon name,通過Category對UIImageView增加IBInspectable類型的 iconName屬性,匹配iconNameString對應的Unicode。

@implementation UIImageView (ZanIconFont) - (void)setIconName:(NSString *)iconNameString { ZanIconName iconName = [ZanIconFont iconNameWithString:iconNameString]; if (!iconName) { return; } [self setImage:[ZanIconFont imageWithIcon:iconName imageSize:self.bounds.size tintColor:self.tintColor]]; } @end 

 

imageViewCategory

在Android中使用

可參考開源庫 iconify

總結

起初Iconfont在web中使用比較流行,在App中使用較少,但是目前看來很多大廠的App也紛紛使用起來,Iconfont的接入給我們項目帶來了很多的方便,同時也可以解決我們在模塊化過程中不同模塊之間重復圖片的問題,總之利大於弊,小伙伴們趕緊用起來吧。

參考

使用IconFont減小iOS應用體積 dzenbot/Iconic


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM