列数をダイレクトに設定する方法はないので、画面のサイズから必要な列数に合うセルのサイズを計算して設定する。
他に UICollectionViewDelegateFlowLayout
プロトコルを実装したクラスを作成する方法があったが、恐らく下記の collectionView からLayoutを取り出して itemSize を直接設定する方法が一番簡単だと思う。
if let layout = collection.collectionViewLayout as? UICollectionViewFlowLayout{
let cellWidth = floor(collectionView.bounds.width / 7) // *7列*
layout.itemSize = CGSizeMake(cellWidth, cellWidth)
// ここからはオプション マージンとかをなくしている
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.minimumInteritemSpacing = 0 // アイテム間?
layout.minimumLineSpacing = 0 // 行間
}
//* 下記はViewController で指定する (マージン対策)
// これを設定するとスーパービューに自動で入るマージン(32pt)がなくなり、ピッタリ収まる。
// ただしレイアウト的にはあまりかっこよくないので、マージンを計算に入れてセルのサイズを決定するとより良いでしょう
// 詳しくはこの記事の下で
override func viewWillLayoutSubviews() {
self.view.layoutMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
ただ UICollectionViewDelegateFlowLayout
プロトコルを使用する場合も collectionView の delegate に UICollectionViewDelegateFlowLayout
のメソッドを追加するだけなので、そう変わりはない。てっとり早い方法が上なだけ。
また delegateFlowLayout が collectionView:layout:sizeForItemAtIndexPath:
を実装していない時にしか有効にならない
If the delegate does not implement the collectionView:layout:sizeForItemAtIndexPath: method, the flow layout uses the value in this property to set the size of each cell. This results in cells that all have the same size.
レイアウト崩れ対策
ViewController の viewWillLayoutSubviews の直前で self.view.layoutMargins で自動的にマージンが作られるので、これをセルのサイズの計算に入れないとレイアウトが崩れてしまう。
計算に入れずに強引に対応するには、上記のコードの通りだが viewWillLayoutSubviews を override してその処理の中で layoutMargins を上書きしてしまえば良い。
viewDidLoad でlayoutMarginsを指定しても、その後 viewWillLayoutSubviews までの間で上書きされてしまうので注意。