# 한 줄당 사진 개수 고정하기
- 디바이스 크기, 가로/세로 모드에 관계없이 항상 한 줄에는 사진이 4개가 보이도록 하는 게 과제!

# viewWillLayoutSubviews()
- SwiftUI 에서는 그리드 열 개수를 지정할 수 있었어서 UIKit 에도 있겠거니 했는데 공식문서를 보니 없는 것 같았다...킹짱 구글에게 물어봤는데 결국 수동으로 계산해서 적용해야 된다는 게 답이었다...그래서 실버였구나...ㅎㅎㅎ
- 아무튼 n개 열을 나타내기 위한 아이템의 너비를 구하려면 collectionView 의 width 에서 아이템을 제외한 모든 여백의 너비를 뺀 다음, 그 값을 n 으로 나누면 된다.
- 책에서는 viewDidLayoutSubviews() 메서드에서 작업을 해보랬는데, 이렇게 하니까 일단 subview 들을 디스플레이한 직후에 변경이되다보니 아래처럼 일시적으로 오렌지색 셀이 보이고 그 다음에 바뀐 너비에 맞게 조정이 이루어졌다.

- 그리고 viewDidLoad() 메서드에서 bounds 의 변경에 따라 content area 를 다시 계산할 때, 항상 safe area inset 을 고려하도록 해줬다. 이렇게 안하면 가로모드로 넘어갔을 때 사진이 양 옆에 safe area 를 무시하고 퍼져서 이렇게 보기 싫게 된다

class PhotosViewController: UIViewController, UICollectionViewDelegate,
UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
collectionView.dataSource = photoDataSource
collectionView.delegate = self
collectionView.contentInsetAdjustmentBehavior = .always
...
}
override func viewDidLayoutSubviews() {
guard let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
return
}
let columns: CGFloat = 4
let marginsAndInsets = layout.sectionInset.left +
layout.sectionInset.right +
collectionView.safeAreaInsets.left +
collectionView.safeAreaInsets.right +
layout.minimumInteritemSpacing * CGFloat(columns - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / columns).rounded(.down)
layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
}
}
- 그래서 아예 subview 들의 viewWillLayoutSubviews() 메서드로 작업을 옮겨줬다.

# collectionView(_:layout:sizeForItemAt:)
- 공식문서를 보다가 이 메서드를 UICollectionViewDelegateFlowLayout 프로토콜을 따르는 클래스에서 구현하면, flow layout 이 해당 메서드의 리턴값을 아이템의 사이즈로 사용한다는 것을 발견했다.
- 그래서 viewWillLayoutSubviews() 에 있던 로직을 그대로 이 메서드로 옮겨줬더니, 여전히 잘 작동됐다!
class PhotosViewController: UIViewController, UICollectionViewDelegate,
UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
let columns: CGFloat = 4
let marginsAndInsets = layout.sectionInset.left +
layout.sectionInset.right +
collectionView.safeAreaInsets.left +
collectionView.safeAreaInsets.right +
layout.minimumInteritemSpacing * CGFloat(columns - 1)
let itemWidth = ((collectionView.bounds.size.width - marginsAndInsets) / columns).rounded(.down)
return CGSize(width: itemWidth, height: itemWidth)
}
}
- 유사하게, collectionView(_:layout:insetForSectionAt:)
등의 메서드를 사용해서 flow layout 의 section inset, minimum line spacing, minimum inter item spacing 등을 반환할 수 있는데, 주의할 점은 flow layout 자체의 값이 바뀌는 것은 아니라는 점!