結果
左上から詰めるようなよくあるViewですが、レイアウトが無いので自分で組まなきゃいけないという、個人的に萎えるパーツの代表格です。(確かAndroidなら割と簡単ですよね)
私はこれまで3回組んでいますが、もういい加減このViewに時間を掛けるのがいやになったのでパーツ化しました。(たぶんどこかで既出だと思いますが)
コードはこちら
https://github.com/osanaikoutarou/TagsViewSample
もちろんdidSelectItemAtIndexPathで選択可能です
どのようにパーツ化するか
cellSizesと、horizontalMarginと、verticalMargin、そして全体の枠であるinsetを、カスタムLayoutに設定します。
let layout = TagsCollectionViewLayout()
// 呼び出し
layout.setup(cellSizes: cellSizes,
horizontalMargin: 10,
verticalMargin: 10,
collectionViewInset: UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15))
collectionView.setCollectionViewLayout(layout, animated: false)
中身はゴニョゴニョ計算しています
/// レイアウトを指定,左上詰めで計算する
///
/// - Parameters:
/// - cellSizes:左上から順のサイズ
/// - horizontalMargin: cell同士のmargin 上下
/// - verticalMargin: cell同士のmargin 左右
/// - collectionViewInset: 全体のInset
func setup(cellSizes:[CGSize], horizontalMargin:CGFloat, verticalMargin:CGFloat, collectionViewInset:UIEdgeInsets) {
self.cellSizes = cellSizes
self.horizontalMargin = horizontalMargin
self.verticalMargin = verticalMargin
self.collectionViewInset = collectionViewInset
// 左上から並べていきます
var currentPoint:CGPoint = CGPoint(x: collectionViewInset.top, y: collectionViewInset.left)
var currentRowHeight:CGFloat = 1
for (i, size) in cellSizes.enumerated() {
let indexPath = IndexPath(row: i, section: 0)
if (currentPoint.x + size.width <= collectionViewWidth - collectionViewInset.left - collectionViewInset.right) {
// 収まる
let frame = CGRect(x: currentPoint.x, y: currentPoint.y, width: size.width, height: size.height)
cellFrames[indexPath] = frame
if (currentRowHeight < size.height) {
currentRowHeight = size.height
}
currentPoint.x += size.width + horizontalMargin
}
else {
// 改行したうえで
currentPoint.x = collectionViewInset.left
currentPoint.y += currentRowHeight + verticalMargin
currentRowHeight = 1
if (currentPoint.x + size.width <= collectionViewWidth - collectionViewInset.left - collectionViewInset.right) {
// 収まる
let frame = CGRect(x: currentPoint.x, y: currentPoint.y, width: size.width, height: size.height)
cellFrames[indexPath] = frame
if (currentRowHeight < size.height) {
currentRowHeight = size.height
}
currentPoint.x += size.width + horizontalMargin
}
else {
// 収まらない
currentPoint = CGPoint(x: 0, y: currentPoint.y + verticalMargin + currentRowHeight)
currentRowHeight = 1
let frame = CGRect(x: currentPoint.x,
y: currentPoint.y,
width: collectionViewWidth,
height: size.height)
cellFrames[indexPath] = frame
if (currentRowHeight < size.height) {
currentRowHeight = size.height
}
currentPoint.x = collectionViewInset.left
}
}
}
}
任意の位置にセルを配置するための方法については、毎度こちらを参考にしています。
ありがとうございます。
https://dev.classmethod.jp/smartphone/iphone/ios6-uicollectionview-customlayout/
cellSizesには何を渡すか
横幅が無制限だった際のcellSizeです
例えば長い文章だとwidthが1000などになるかもしれません。そのまま渡せば良いように計算します
積み残し TODO
・改行処理(2行で表示したいなど)
・複雑なUIの場合
・もっとパーツ然としていたほうが良いですかね?