アイコン
テキスト
FontAwesome
Swift2

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

More than 1 year has passed since last update.

今回作りたかったのは下の画像のボタンです。

sample.png

FontAwesome Swiftをよく利用させてもらっているのですが、画像のようなサンプルが見当たらなかったので自作していました。

iOSアプリ制作を初めてまだ時間が経っていないので、いい作りとは言えないのですが、ひとまず思った通りのことまでできたため、コードの掲載をします。

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


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

  (シミュレータでiOS4 / iOS5 / iOS6 / iPad Air)での目視確認テストをしたところ、

画像と同様の表示が確認できたため、実用上問題はなさそうという判断をして使っています。


  1. 上下アイコンのボタンの配置を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.
}

}

```