標籤雲

今天要來實作一個 hashtag 標籤雲,我們可以使用 UICollectionView 搭配 UICollectionViewFlowLayout 來實現畫面:

  1. 設置好 minimumLineSpacing, minimumInteritemSpacing, sectionInset
  2. 動態計算好每個 hashtag 的長度
  3. 調整 collectionView 的高度(可以透過 collectionView contentSize height 取得內容高度)
  4. 自信滿滿的編譯!


這標籤雲有點漏風啊

因為 UICollectionViewFlowLayout 會自適應長度將 cell 填滿,所以每一列的 tag 中間都有不同的間距,看起來像是牙齒缺了幾個洞…

這時我們不經想起UILabel 的 text alignment,不過翻找了一下 UICollectionViewFlowLayout 似乎沒有這樣方便的設定


客製化靠左對齊的 UICollcetionViewLayout

為了標籤雲整體的美觀,我們可以透過建立一個客製化的 LeftAlignedCollectionViewFlowLayout 並覆寫 layoutAttributesForElements 來改變既定的物件排列位置:


class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
var leftMargin = sectionInset.left
var maxY: CGFloat = -1.0
attributes?.forEach { layoutAttribute in
if layoutAttribute.frame.origin.y >= maxY {
leftMargin = sectionInset.left
}
layoutAttribute.frame.origin.x = leftMargin
leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
maxY = max(layoutAttribute.frame.maxY , maxY)
}
return attributes
}
}

line 4: 取得所有的 layout attributes

line 6: x 座標的起始位置為 sectionInset.left

line 7: 預設最大 Y 座標為負數,待會會作為判斷換行用

line 8: 遍歷所有的 layout attributes,我們要手動調整 collection view 內容的位置

line 9~11: 判斷 collection view cell 是否換行,如果是新的一行,將 left margin 設定回初始值

line 13: 改變 layout attributes 的 x 座標

line 15: 更新下一個 tag 的起始位置

line 16: 更新最大 Y 值,如果 tag 已經換到下一行,在 line 9 的判斷會將 left margin 設定回初始值

 

效果圖

使用客製的 let flowLayout = LeftAlignedCollectionViewFlowLayout( ) ,標籤雲就乖乖靠左對齊囉