背景
UICollectionView 内に、1行につき4つずつセルを並べようとしてもなぜか画面の外まではみ出してしまい苦労したので解決方法を残します。
元のコード
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let sectionInsets = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset ?? .zero
let interItemSpacing = 10.0 // セル間のスペース
let numberOfItemsPerRow = 4.0
// Safe Area を考慮した幅から、左右のインセットとセル間のスペースを引く
let totalSpacing = sectionInsets.left + sectionInsets.right + (interItemSpacing * (numberOfItemsPerRow - 1))
let availableWidth = collectionView.safeAreaLayoutGuide.layoutFrame.width - totalSpacing
// セルの幅を計算
let width = availableWidth / numberOfItemsPerRow
return CGSize(width: width, height: 80)
}
原因
collectionView(_:layout:sizeForItemAt:)
でセルのサイズを指定するだけでは、レイアウトが自動的に再描画されないためでした。
collectionView(_:layout:sizeForItemAt:)
は、セルのサイズを要求されたときにそのサイズを提供するためのメソッドであり、再レイアウトや再描画をトリガーするメソッドではありません。
対応
viewDidLayoutSubviews()
でレイアウトを無効化し、再度レイアウトを計算することで、最終的な正しいレイアウトが適用されます。
invalidateLayout()
を呼び出すことで、コレクションビューが表示された後に正しいサイズで再レイアウトされます。
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// レイアウトを再計算
collectionView.collectionViewLayout.invalidateLayout()
}