Swift2 FontAwesomeアイコンとテキストを併用したボタンを作成する

今回作りたかったのは下の画像のボタンです。
![sample.png](https://qiita-image-store.s3.amazonaws.com/0/57579/ba0c8a72-55ee-676f-f7c1-734a7d70e2c6.png)

[FontAwesome Swift](https://github.com/thii/FontAwesome.swift)をよく利用させてもらっているのですが、画像のようなサンプルが見当たらなかったので自作していました。
iOSアプリ制作を初めてまだ時間が経っていないので、いい作りとは言えないのですが、ひとまず思った通りのことまでできたため、コードの掲載をします。

**このサンプルコードの中で、やっつけでやってしまっている箇所が２箇所あります。**

1. 左右にテキストとアイコンを配置したときに生じる、ベースラインずれの差を埋めるための方法が観測値から算出した計算値になっていて、この計算根拠が目視を用いたものになっているため、環境によって多分に微妙なずれが生じる可能性が高いこと

```
  (シミュレータでiOS4 / iOS5 / iOS6 / iPad Air)での目視確認テストをしたところ、
  画像と同様の表示が確認できたため、実用上問題はなさそうという判断をして使っています。
```

2. 上下アイコンのボタンの配置を2重改行で対応してしまっていること

```
　Paragraphでline heightを設定し、TextAlignをCenterにしておけば自然と中央揃えになるかと
　見込んでいたのですが、アイコンだけ左端に表示される現象が確認され、改行を与えた場合に
　期待通りの表示になったため、サンプルソース上では2重改行で余白調整をしてしまっています。
　こちらも1と同様に調整のための修正が非常にイケテナイので、
　あくまで参考として利用いただくのがよいかと思います。
```

NSMutableAttributedStringの利用例の一つになり、制作のアイデアの一つになれればよいかなと。

**こうしたらやっつけじゃなくなったよ！！というご意見は大絶賛募集しております。。。**

**以下コード**
```UIFontAwesomeButton.swift
import UIKit
import FontAwesome_swift

enum AwesomeIconAlignment {
    case top
    case bottom
    case left
    case right
}

@IBDesignable
class UIFontAwesomeButton: UIButton {
    
    func setAwesomeMixTitle(awesomeFontType: FontAwesome, AwesomeFontSize: CGFloat, titleText: String, iconAlign: AwesomeIconAlignment = .left, AwesomeFontColor: UIColor! = nil, titleTextFontName: String = "", titleTextFontSize: CGFloat = 0, titleTextColor: UIColor! = nil) {
        
        // Awesomefontの設定
        let afColor = AwesomeFontColor == nil ? self.titleLabel?.textColor : AwesomeFontColor
        let btnIcon = String.fontAwesomeIconWithName(awesomeFontType)
        var btnAttr = NSMutableAttributedString(string: btnIcon)
        btnAttr.addAttributes([NSForegroundColorAttributeName: afColor], range: NSMakeRange(0, btnIcon.characters.count))
        btnAttr.addAttributes([NSFontAttributeName: UIFont.fontAwesomeOfSize(AwesomeFontSize)], range: NSMakeRange(0, btnIcon.characters.count))
        
        // 通常テキスト設定
        let titleAttributeText = NSMutableAttributedString(string: titleText)
        let fontName = titleTextFontName == "" ? self.titleLabel?.font.fontName : titleTextFontName
        let fontSize = titleTextFontSize <= 0 ? self.titleLabel?.font.pointSize : titleTextFontSize
        if titleText != "" {
            let txtColor = titleTextColor == nil ? self.titleLabel?.textColor : titleTextColor
            titleAttributeText.addAttributes([NSFontAttributeName: UIFont(name: fontName!, size: fontSize!)!], range: NSMakeRange(0, titleText.characters.count))
            titleAttributeText.addAttributes([NSForegroundColorAttributeName: txtColor], range: NSMakeRange(0, titleText.characters.count))
        }
        
        switch iconAlign {
        case .top:
            let separaterChar = NSMutableAttributedString(string: "\n\n")
            separaterChar.addAttributes([NSFontAttributeName: UIFont(name: fontName!, size: fontSize! * 0.3)!], range: NSMakeRange(0, separaterChar.length))
            btnAttr.appendAttributedString(separaterChar)
            btnAttr.appendAttributedString(titleAttributeText)
        case .bottom:
            let separaterChar = NSMutableAttributedString(string: "\n\n")
            separaterChar.addAttributes([NSFontAttributeName: UIFont(name: fontName!, size: fontSize! * 0.3)!], range: NSMakeRange(0, separaterChar.length))
            
            separaterChar.appendAttributedString(btnAttr)
            titleAttributeText.appendAttributedString(separaterChar)
            btnAttr = titleAttributeText
        case .left:
            let baseLineHieght:CGFloat = getBaseLineHeight(AwesomeFontSize, fontSize: fontSize!)
            if AwesomeFontSize >= fontSize! {
                titleAttributeText.addAttribute(NSBaselineOffsetAttributeName, value: baseLineHieght, range: NSMakeRange(0, titleAttributeText.length))
            } else if AwesomeFontSize < fontSize! {
                btnAttr.addAttribute(NSBaselineOffsetAttributeName, value: baseLineHieght, range: NSMakeRange(0, btnAttr.length))
            }
            btnAttr.appendAttributedString(titleAttributeText)
        case .right:
            let baseLineHieght:CGFloat = getBaseLineHeight(AwesomeFontSize, fontSize: fontSize!)
            if AwesomeFontSize > fontSize! {
                titleAttributeText.addAttribute(NSBaselineOffsetAttributeName, value: baseLineHieght, range: NSMakeRange(0, titleAttributeText.length))
            } else if AwesomeFontSize < fontSize! {
                btnAttr.addAttribute(NSBaselineOffsetAttributeName, value: baseLineHieght, range: NSMakeRange(0, btnAttr.length))
            }
            titleAttributeText.appendAttributedString(btnAttr)
            btnAttr = titleAttributeText
        }
        
        self.titleLabel?.numberOfLines = 0
        self.titleLabel?.textAlignment = .Center
        self.setAttributedTitle(btnAttr, forState: .Normal)
    }

    /**
     テキストとFontawesomeのサイズが異なるとベースライン下基準になってしまうため、垂直中央によるようにLineHeightを計算する。
     計算は fontawesome / 2 - font / 2 でフォントを中央分割した後での高さの差を求め、その値の平方根を取得し、
     さらにその平方根の平方根を足した値になる。値の根拠は観察値から導き出したものであるので、環境の変化に非常に弱い。
     よって適用する環境をよく観察してオフセット値の算出をする必要がある。
     
     - parameter AwesomeFontSize: FontAwesomeのフォントサイズ
     - parameter fontSize:        テキストのフォントサイズ
     
     - returns: ベースラインオフセット
     */
    private func getBaseLineHeight(AwesomeFontSize: CGFloat, fontSize: CGFloat) -> CGFloat {
        var baseLineHieght:CGFloat = sqrt(abs(AwesomeFontSize / 2 - fontSize / 2)) + sqrt(sqrt(abs(AwesomeFontSize / 2 - fontSize / 2)))
        if abs(AwesomeFontSize / 2 - fontSize / 2) > 10.0 {
            baseLineHieght = baseLineHieght + sqrt(sqrt(abs(AwesomeFontSize / 2 - fontSize / 2)))
        } else if baseLineHieght == 0 {
            baseLineHieght = 0.5
        }
        return baseLineHieght
    }
    
    // viewの枠線の色
    @IBInspectable var borderColor: UIColor = UIColor.clearColor() {
        didSet {
            self.layer.borderColor = borderColor.CGColor
        }
    }
    
    // viewの枠線の太さ
    @IBInspectable var borderWidth: CGFloat = 0 {
        didSet {
            self.layer.borderWidth = borderWidth
        }
    }
    
    // viewの角丸
    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            self.layer.cornerRadius = cornerRadius
            self.layer.masksToBounds = true
        }
    }
}
```


**呼び出しサンプル**
``` ViewController.swift
import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var btnTop: UIFontAwesomeButton!
    @IBOutlet weak var btnBottom: UIFontAwesomeButton!
    @IBOutlet weak var btnLeft: UIFontAwesomeButton!
    @IBOutlet weak var btnRight: UIFontAwesomeButton!
    @IBOutlet weak var btnLeft30_12: UIFontAwesomeButton!
    @IBOutlet weak var btnRight30_12: UIFontAwesomeButton!
    @IBOutlet weak var btnLeft12_30: UIFontAwesomeButton!
    @IBOutlet weak var btnRight12_30: UIFontAwesomeButton!
    @IBOutlet weak var btnLeft46_8: UIFontAwesomeButton!
    @IBOutlet weak var btnRight46_8: UIFontAwesomeButton!
    @IBOutlet weak var btnLeft8_46: UIFontAwesomeButton!
    @IBOutlet weak var btnRight8_46: UIFontAwesomeButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        btnTop.setAwesomeMixTitle(
            .Search, AwesomeFontSize: 28
            , titleText: "上アイコン"
            , iconAlign: .top
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "HiraginoSans-W3"
            , titleTextFontSize: 14.0
            , titleTextColor: UIColor.grayColor())

        btnBottom.setAwesomeMixTitle(
            .User, AwesomeFontSize: 38
            , titleText: "下アイコン"
            , iconAlign: .bottom
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "HiraginoSans-W3"
            , titleTextFontSize: 14.0
            , titleTextColor: UIColor.grayColor())

        btnLeft.setAwesomeMixTitle(
            .User, AwesomeFontSize: 24
            , titleText: " 左アイコン"
            , iconAlign: .left
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "Helvetica Bold Oblique"
            , titleTextFontSize: 24
            , titleTextColor: UIColor.whiteColor())

        btnRight.setAwesomeMixTitle(
            .User, AwesomeFontSize: 24
            , titleText: "右アイコン "
            , iconAlign: AwesomeIconAlignment.right
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "HiraginoSans-W3"
            , titleTextFontSize: 24
            , titleTextColor: UIColor.grayColor())

        btnLeft30_12.setAwesomeMixTitle(
            .User, AwesomeFontSize: 30
            , titleText: " 左アイコン"
            , iconAlign: .left
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "Helvetica Bold Oblique"
            , titleTextFontSize: 12
            , titleTextColor: UIColor.whiteColor())
        
        btnRight30_12.setAwesomeMixTitle(
            .User, AwesomeFontSize: 30
            , titleText: "右アイコン "
            , iconAlign: AwesomeIconAlignment.right
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "HiraginoSans-W3"
            , titleTextFontSize: 12
            , titleTextColor: UIColor.grayColor())

        btnLeft12_30.setAwesomeMixTitle(
            .User, AwesomeFontSize: 12
            , titleText: " 左アイコン"
            , iconAlign: .left
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "Helvetica Bold Oblique"
            , titleTextFontSize: 30
            , titleTextColor: UIColor.whiteColor())
        
        btnRight12_30.setAwesomeMixTitle(
            .User, AwesomeFontSize: 12
            , titleText: "右アイコン "
            , iconAlign: AwesomeIconAlignment.right
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "HiraginoSans-W3"
            , titleTextFontSize: 30
            , titleTextColor: UIColor.grayColor())

        btnLeft46_8.setAwesomeMixTitle(
            .User, AwesomeFontSize: 46
            , titleText: " 左アイコン"
            , iconAlign: .left
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "Helvetica Bold Oblique"
            , titleTextFontSize: 8
            , titleTextColor: UIColor.whiteColor())
        
        btnRight46_8.setAwesomeMixTitle(
            .User, AwesomeFontSize: 46
            , titleText: "右アイコン "
            , iconAlign: AwesomeIconAlignment.right
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "HiraginoSans-W3"
            , titleTextFontSize: 8
            , titleTextColor: UIColor.grayColor())
        
        btnLeft8_46.setAwesomeMixTitle(
            .User, AwesomeFontSize: 8
            , titleText: " 左アイコン"
            , iconAlign: .left
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "Helvetica Bold Oblique"
            , titleTextFontSize: 46
            , titleTextColor: UIColor.whiteColor())
        
        btnRight8_46.setAwesomeMixTitle(
            .User, AwesomeFontSize: 8
            , titleText: "右アイコン "
            , iconAlign: AwesomeIconAlignment.right
            , AwesomeFontColor: UIColor.orangeColor()
            , titleTextFontName: "HiraginoSans-W3"
            , titleTextFontSize: 46
            , titleTextColor: UIColor.grayColor())
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}
```