App中使用Iconfont的整套方案

什么是Iconfont

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

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

優點

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

缺點

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

如何制作Iconfont

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

iconfont

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

zan-iconfont

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

將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/目錄下有個示例配置文件,可以參考??聪挛覀兊呐渲梦募糠纸貓D:

configfile
configfile

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

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

最終會生成如下一些文件

iconfontfile

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

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

在App中使用

在iOS中使用

先看下簡單的demo

icondemo

首先把上面制作的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的接入給我們項目帶來了很多的方便,同時也可以解決我們在模塊化過程中不同模塊之間重復圖片的問題,總之利大于弊,小伙伴們趕緊用起來吧。

參考

http://johnwong.github.io/mobile/2015/04/03/using-icon-font-in-ios.html
https://github.com/dzenbot/Iconic

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一.iconfont使用場景(優缺點); 一般我們項目決定要使用一個技術點前,會查相關資料對其有大概的理解。例如,...
    蕭強閱讀 1,640評論 1 6
  • 什么是iconFont iconFont顧名思義是字體圖標,圖標就藏在字體文件里面,看著是個圖標,其實卻是個文字,...
    cocolove2閱讀 15,695評論 4 10
  • 什么是 iconfont iconfont就是字面上的意思,叫做“字體圖標”,將一套圖標集以字體文件的形式封裝,并...
    Judicy閱讀 9,100評論 6 11
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,264評論 25 708
  • 1.SVN、GIT、CVS及Mercurial的比較 https://wenku.baidu.com/view/2...
    hypercode閱讀 511評論 0 0