iOS - iconfont 的使用

2019-01-26

iconfont 是什么 ?

顾名思义,就是 icon + font,通过一个包含各种 icon 的字体文件(.ttf文件)来显示图标的方式。

为什么要使用 iconfont ?

  1. 更加轻量,字体文件大小相比 png 要小
  2. 图标保真,放大缩小不会失真,无需准备 @2x、@3x 多倍图
  3. 容易修改 icon 颜色
  4. 管理方便,只有一个字体文件,每个 icon 对应一个 unicode。

iconfont 完美无缺?

不,iconfont 也有一些缺点

  1. 只适用于简单图标,对于一些有纹理的图片没办法使用
  2. 无法直接预览,需要通过 unicode 找到对应的图标才能预览

代码

1.生成 iconfont

通过 iconfont.cnicomoon.iofontawesome 平台直接进行可视化的操作选择 icon 并下载后就可以生成指定的 iconfont 文件,对于我们 iOS,我们需要的只有其中的 iconfont.ttf 文件

There are some free icons can be used for commercial purposes, please refer to 18 Websites To Download The Best Free Icons For Commercial Use.

2.添加 iconfont.ttf 至项目中

3.使用

这里只展示 UILabel、UIImage 生成图标的方式,其余的如 UIBarButtonItem、UIButton 的使用均可以通过相同方法实现

  1. 加载字体文件
static func loadFont() -> Bool {

    let fontName = "iconfont"

    if UIFont.fontNames(forFamilyName: fontName).count > 0 {
        return true
    }

    guard let filePath = Bundle.main.path(forResource: fontName, ofType: "ttf"),
    let fontData = NSData(contentsOfFile: filePath),
    let dataProvider = CGDataProvider(data: fontData),
    let cgFont = CGFont(dataProvider) else {
        return false
    }

    var error: Unmanaged<CFError>?

    if !CTFontManagerRegisterGraphicsFont(cgFont, &error) {
        let errorDescription: CFString = CFErrorCopyDescription(error!.takeUnretainedValue())
        print("Unable to load font: %@", errorDescription, terminator: "")
        return false
    }

    return true
}
  1. UILabel 显示图标

UILabel 显示图标是通过 attributedText 属性,指定字体为 iconfont.ttf,指定字体大小、颜色,即可生成指定图标

extension UILabel {
    
    public func iconFont(size fontSize: CGFloat, unicode: String, color: UIColor? = nil) {
        var attributes = [NSAttributedString.Key: Any]()
        attributes[NSAttributedString.Key.font] = UIFont(name: "iconfont", size: fontSize)
        if let color = color {
            attributes[NSAttributedString.Key.foregroundColor] = color
        }
        
        let attributedString = NSAttributedString(string: unicode, attributes: attributes)
        
        self.attributedText = attributedString
    }
    
}
  1. UIImage 显示图标

UIImage 显示图标则是将一个NSAttributedString 通过 Core Graphics 绘制成一个 UIImage 生成 icon

extension UIImage {
    
    public static func iconFont(fontSize: CGFloat, unicode: String, color: UIColor? = nil) -> UIImage {
        var attributes = [NSAttributedString.Key: Any]()
        attributes[NSAttributedString.Key.font] = UIFont(name: "iconfont", size: fontSize)
        if let color = color {
            attributes[NSAttributedString.Key.foregroundColor] = color
        }
        let attributedString = NSAttributedString(string: unicode, attributes: attributes)
        
        let rect = attributedString.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: fontSize), options: .usesLineFragmentOrigin, context: nil)
        
        let imageSize: CGSize = rect.size
        UIGraphicsBeginImageContextWithOptions(imageSize, false, UIScreen.main.scale)
        
        attributedString.draw(in: rect)
        
        let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        
        return image
    }
}
  1. 使用
// 加载字体
UIFont.loadFont()

let label = UILabel()
let imageView = UIImageView()

// UILabel 显示图标
label.iconFont(size: 40, unicode: "\u{e656}")
// 通过 UIImage 显示图标
imageView.image = UIImage.iconFont(fontSize: 50, unicode: "\u{e651}", color: .red)

4.更好的使用方式

以上通过 硬编码使用 unicode 设置图标并不是很理想。首先语义不清,一个 unicode 表示的图标什么意思无法直观的表示;其次对于多次重复使用一个图标,每次使用都要翻一翻说明文件才能知道对应的 unicode 那么在 swift 中我通过定义一个枚举类型表示所有的图标,那么在使用的时候回方便很多。 具体实现可以看 IconFont,其中自带 FontAwesome 字体库,以及可以使用自定义的 iconfont

使用

Create

public enum CustomIconFont: String {
    case feedback = "\u{e656}"
    case search = "\u{e651}"
    case home = "\u{e64f}"
    case clock = "\u{e648}"
    case like = "\u{e643}"
    case shoppingCart = "\u{e63f}"
}

extension CustomIconFont: IconFontType {
     // iconfont.ttf 的文件路径
    public static var fontFilePath: String? = Bundle.main.path(forResource: "iconfont", ofType: "ttf")
    // 字体名
    public static var fontName: String {
        return "iconfont"
    }

    public var unicode: String {
        return self.rawValue
    }
}

Usage

label1.iconFont(size: 25, icon: CustomIconFont.clock, color:color)
label2.iconFont(size: 30, icon: CustomIconFont.feedback, color: color)

Preference:

  1. iconfont.cn
  2. icomoon.io
  3. fontawesome
  4. 18 Websites To Download The Best Free Icons For Commercial Use, thank Virgy for sharing this.