기존 UICollectionViewLayout으로는 구현하기 힘든 여러 가지 UI들을 적용가능
각 섹션마다 서로 다른 레이아웃을 가지는 데도 쉽게 관리할 수 있음
기존 Layout은 하나의 콜렉션 뷰로 다양한 레이아웃을 가진 ScrollView를 갖기 쉽지 않음
예를 들어 요즘 앱들에서 많이 보이는 이런 디자인들..
func createBasicLayout() -> NSCollectionLayoutSection {
/// 각 item의 사이즈 설정 ( width: 120, height: 160 )
let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(120.0), heightDimension: .absolute(160.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
/// 아이템의 마진 값 설정
item.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4)
/// 아이템들이 들어갈 Group 설정
/// groupSize 설정
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.9), heightDimension: .absolute(160.0))
/// subitem에 item을 넣어주고 각 그룹 당 아이템이 보여질 갯수는 3개
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 3)
/// 최종적으로 section 설정
let section = NSCollectionLayoutSection(group: group)
/// 헤더 생성
let titleHeader = createTitleHeaderLayout()
/// 이 Layout은 헤더를 보여지도록 적용
section.boundarySupplementaryItems = [ titleHeader ]
/// 어떤 형식의 스크롤을 쓸지 결정
section.orthogonalScrollingBehavior = .continuous
return section
}
먼저 NSCollectionLayoutSection을 만들어주는 메서드 구현
위에서 말했 듯이 Item, Group, Section 순으로 만들어주고 차례차례 인자로 넣어주는 것이 보임
func createLayout() -> UICollectionViewCompositionalLayout {
/// return 값인 UICollectionViewCompositionalLayout은 콜백 함수로 두 개의 인자가 나온다.
///
/// 콜백 함수 :
/// sectionNumber [int] : sectionNumber마다 다르게 줄 수 있도록하는 인자
/// env [NSCollectionLayoutEnvironment] : 사이즈, 인셋 등을 줄 수 있는 인자
/// return [NSCollectionLayoutSection] : 만들어두었던 NSCollectionLayoutSection 객체를 넣어주면 최종적으로 Layout으로 반환됨
return UICollectionViewCompositionalLayout {[weak self] sectionNumber, env -> NSCollectionLayoutSection? in
/// section 번호마다 다른 Layout을 설정하기 위해 switch 문
switch sectionNumber {
case 0:
return self?.createMainLayout()
default:
return self?.createBasicLayout()
}
}
}
최종 적으로 UICollectionView에 넣을 수 있는 Layout객체로 반환해주는 메서드 구현
굳이 Section과 Layout을 반환하는 메서드를 나눈 이유는
반환 값인 UICollectionViewCompositionalLayout의 콜백함수의 리턴 타입을 보면 알 수 있다.
코드를 보면 sectionNumber로 switch구문을 작성한 것이 눈에 띰
반환값인 UICollectionViewCompositionalLayout은 콜백함수로 섹션 번호랑, 레이아웃의 환경을 설정할 수 있는 인자를 반환받음
여기서 모든 레이아웃을 한꺼번에 만들 수 있지만, 그러면 한 메서드 안에 코드가 너무 복잡해져 필자는 따로 나누는 것을 추천
왜 UICollectionViewCompositionalLayout이라는 값은 콜백함수로 이런 값을 가지는가?
생각해보면 섹션 마다 각 커스텀한 레이아웃을 갖고 있을 것이기 때문에 이렇게 되어있는 것이 어찌보면 당연하다.
lazy var collectionView: UICollectionView = {
let layout = createLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(MovieCollectionViewCell.self, forCellWithReuseIdentifier: MovieCollectionViewCell.identifier)
collectionView.register(MovieMainCollectionViewCell.self, forCellWithReuseIdentifier: MovieMainCollectionViewCell.identifier)
collectionView.register(MovieCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: MovieCollectionHeaderView.identifier)
collectionView.dataSource = self
return collectionView
}()
최종적으로 collectionView를 초기화 할 떄
createLayout() 메서드를 반환 받아서 섹션 마다 다른 레이아웃을 갖고 있는 레이아웃 객체를 생성
이제 섹션 마다 서로 다른 레이아웃을 갖고 있는 collectionView를 가질 수 있게 된다.
일반적으로 각 섹션마다 동일한 레이아웃을 사용할 거면 그냥 사용했던 UICollectionViewLayout을 사용하면 편할 것이라고 생각한다.
그런데 요즘 앱 트렌드 상 재밌는 UI들이 많이 출시하기 때문에 알아둬야 한다고 생각한다.