UILabelを利用して、↓の写真のようなタグっぽい見た目のviewを実装する。

ざっくり言ってしまえばUILabelにボーダーつけて終わり、なんですがw
まずは1個のタグ
StoryBoardにUIViewControllerをおいて、ViewController.swiftに表示内容を書いていく。
まずはタグ表示に利用するUILabelの子クラスを作成。
initでタグのボーダーや角丸の設定などを行ってしまっている。
プロパティのtagPaddingは、タグ内の文字のパディング幅。
drawRect(_:)をオーバーライドし、UIEdgeInsetsで上下左右にtagPadding分のinsetをつけてdrawTextInRect(_:)でreturnしている。
import UIKit
class TagLabel: UILabel {
    
    let tagPadding: CGFloat = 5
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        layer.cornerRadius = 2
        layer.borderColor = UIColor.blackColor().CGColor
        layer.borderWidth = 1
        textColor = UIColor.blackColor()
        clipsToBounds = true
        numberOfLines = 1
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func drawRect(rect: CGRect) {
        let insets = UIEdgeInsets(top: tagPadding, left: tagPadding, bottom: tagPadding, right: tagPadding)
        return super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))
    }
    
}
続いて、ViewControllerクラスの実装。
tagLabelTextWidth(text:font:height:)メソッドでタグの幅を計算する。
中でやっていることは単純。
- 一度ダミーのインスタンス(UILabel)を生成
- 
sizeToFit()してラベル幅を中のテキストぴったりに合わせ、タグの文字となる部分のwidthを算出
- 上記の値に、左右のパディング幅を加えた値を返す
ということを行っている。
その後、viewDidLoad()内で、算出したタグの幅を利用して本物のTagLabelを作りaddSubview。
class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let tagFont = UIFont.systemFontOfSize(16)
        let tagHeight = tagFont.lineHeight + TagLabel().tagPadding * 2
        let tagText = "hoge"
        let tagWidth = tagLabelTextWidth(text: tagText, font: tagFont, height: tagHeight)
        let tag = TagLabel(frame: CGRectMake(100, 100, tagWidth, tagHeight))
        tag.text = tagText
        tag.font = tagFont
        view.addSubview(tag)
    }
    
    func tagLabelTextWidth(text text: String, font: UIFont, height: CGFloat) -> CGFloat {
        let label = UILabel(frame: CGRectMake(0, 0, CGFloat.max, height))
        label.font = font
        label.text = text
        label.sizeToFit()
        return label.frame.size.width + TagLabel().tagPadding * 2
    }
    
}
以下のような表示がこれでできる。
 
特定のエリアに複数のタグを並べる
今度はこのタグを特定のエリアに複数並べる。
タグとなるキーワード群をwordsという文字列の配列で表現。
先ほど利用したTagLabelのインスタンスをplaceTagsOn(_:tags:)メソッドで複数個生成し、特定のUIView(下記のコード中のtagsView)にaddSubViewしていく。タグを並べる間隔は縦方向も横方向も10pxに設定。
- 表示エリアtagsViewの中でのタグのoriginを設定するため、tagOriginX,tagOriginYを宣言
- 先ほどと同じくタグの横幅をtagLabelTextWidth(text:font:height:)で計算
- この横幅が表示エリアの横幅を超えていたら、超過した長さを切り捨てて表示エリアの横幅と同値に
- 表示エリアの横方向の余白 (areaWidth - tagOriginX) がタグの横幅よりも小さい時、改行して表示したいのでtagOriginX,tagOriginYの値を変更- 改行して左端から表示するのでtagOriginXは0に
- 
tagOriginYに、改行した分の高さ(tagHeight+tagMargin)を加える
 
- 改行して左端から表示するので
- 
tagOriginX,tagOriginYを使ってTagLabelをaddSubview
- 追加したタグ幅(tagWidth + tagMargin)の大きさを、tagOriginXに加える
placeTagsOn(_:tags:)でこれらの処理を繰り返し行うことで、複数のタグを特定のエリア内に配置している。
let words = [
    "Ruby",
    "Ruby on Rails",
    "JavaScript",
    "Swift",
    "iOS",
    "HTML",
    "CSS",
    "Perl",
    "Python",
    "PHP",
    "Java",
    "Scala",
    "Go",
    "Elixir",
    "Objective-C"
]
override func viewDidLoad() {
    super.viewDidLoad()
    
    // (略)
    
    let tagsView = UIView(frame: CGRectMake(50, 200, view.bounds.size.width - 50 * 2, 200))  // 高さは適当な大きさに
    view.addSubview(tagsView)
    placeTagsOn(tagsView, tags: words)
}
func placeTagsOn(tagsView: UIView, tags: [String]) {
    let areaWidth = tagsView.bounds.size.width
    let tagMargin: CGFloat = 10
    let tagFont = UIFont.systemFontOfSize(16)
    let tagHeight = tagFont.lineHeight + TagLabel().tagPadding * 2
    
    var tagOriginX: CGFloat = 0
    var tagOriginY: CGFloat = 0
    
    for tag in tags {
        var tagWidth = tagLabelTextWidth(text: tag, font: tagFont, height: tagHeight)
        if tagWidth > areaWidth {
            tagWidth = areaWidth
        }
        
        if areaWidth - tagOriginX < tagWidth {
            tagOriginX = 0
            tagOriginY += tagHeight + tagMargin
        }
        
        let label = TagLabel(frame: CGRectMake(tagOriginX, tagOriginY, tagWidth, tagHeight))
        label.text = tag
        label.font = tagFont
        tagsView.addSubview(label)
        
        tagOriginX += tagWidth + tagMargin
    }
}
表示は以下のようになり、タグが同間隔で並んでいるのがわかる。
 
