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
}
}
表示は以下のようになり、タグが同間隔で並んでいるのがわかる。