45. 스파르타 코딩 클럽 - UICollectionViewCompositional Layout
🏁 UICollectionView Flowlayout
오늘 스탠다드 분반 수업에서 Compositional Layout을 배웠다.
CollectionView에서 Flowlayout을 이전에 배웠었는데 Flowlayout의 단점을 해결하기 위해
사용하는 Compositional layout을 새로 배웠다.
Flowlayout의 단점
먼저 Flowlayout의 단점이라고 하면, 하나의 CollectionView에 한 가지 레이아웃만 구성할 수 있고,
복잡한 레이아웃은 구성할 수 없는 단점이 있다.
다음과 같은 화면을 구성하기 위해 Flowlayout은 전체를 감싸는 UITableView, UICollectionView 안에
빨간 부분은 UICollectionView, 갈색 부분은 UICollectionView,
초록 부분은 UICollectionView 또는 UITableView
Main UICollectionView 안에 Main Cell 안에 빨간 CollectionView를 추가하고,
빨간 Cell에서 콘텐츠를 구성하게 된다.
이런 방법을 사용하면 코드의 복잡성이 올라가고, 유지보수성은 내려가며, 개발은 어려워진다.
따라서 복잡한 레이아웃을 구현할 때는 Flowlayout보다 Compositional Layout을 사용한다.
🏁 UICollectionView - Compositional Layout
Comositional Layout은 Item, Group, Section, Layout으로 구성된다.
NSCollectionLayoutSize 메서드를 통해 item, group의 크기를 정의한다.
[ Item ]
콜렉션 뷰의 기본 단위인 item의 사이즈와 item을 설정한다.
[ Group ]
Item을 담는 Group이다.
사이즈를 정해주어야 하며 그룹 안에 어떤 아이템을 넣을지 설정 가능하다.
[ Section ]
Group을 담는 Section이다.
스크롤 방향을 설정할 수 있다.
Section에는 group을 담는다.
Section은 Header와 Footer 설정도 가능하다.
🧑💻 실습
실습 내용은 유튜브 뮤직의 레이아웃 잡아보기이다.
0번 Section은 수평 스크롤이며, 한 그룹에 1개의 아이템이 있다.
1번 Section은 수평 스크롤이며, 한 그룹에 4개의 아이템이 있다.
2번 Section은 수직 스크롤이며, 한 그룹에 3개의 아이템이 있다.
1. Collection View 선언 및 생성
// collectionView 생성
private lazy var collectionView: UICollectionView = {
// collectionView의 Layout을 함수로 선언
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: createCompositionalLayout())
collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CustomCollectionViewCell.identifier)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "DefaultCell")
collectionView.register(CustomHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: CustomHeaderView.identifier)
collectionView.delegate = self
collectionView.dataSource = self
return collectionView
}()
2. 선언한 createCompositionalLayout 함수를 구현
private func createCompositionalLayout() -> UICollectionViewCompositionalLayout {
let layout = UICollectionViewCompositionalLayout { sectionIndex, environment in
// sectionIndex를 사용해서 각각의 Section을 처리
switch sectionIndex {
case 0:
// 수평 스크롤 1개 아이템
return self.createOneHorizontalItemTwoGroupSection()
case 1:
// 수평 스크롤 4개 아이템
return self.createFourVerticalItemInOneHorizontalGroupSection()
case 2:
// 수직 스크롤 3개의 아이템
return self.createThreeHorizontalItemInOneVerticalGroupSection()
default:
// 기본 레이아웃
return self.createDefaultSectionLayout()
}
}
// 완성된 layout을 return
return layout
}
3. 각각의 섹션별로 선언한 함수를 구현
3-1. 첫 번째 섹션 함수 구현
// 첫번째 섹션
private func createOneHorizontalItemTwoGroupSection() -> NSCollectionLayoutSection {
// 1. 아이템 사이즈 만들기
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
// 2. 아이템 만들기 (내부 Inset 설정 가능)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = .init(top: 5, leading: 5, bottom: 5, trailing: 5)
// 3. 그룹 사이즈 만들기
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/2.4), heightDimension: .absolute(170))
// 4. 그룹 만들기
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
// 5. 섹션 만들기 (스크롤 방향 설정 가능)
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous
// 6. 헤더 사이즈 만들기
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(40))
// 7. 헤더 만들기
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)
// 8. 헤더 사용
section.boundarySupplementaryItems = [header]
// 9. 섹션 리턴
return section
}
3-2. 두번째 섹션 함수 구현
// 두번째 섹션
private func createFourVerticalItemInOneHorizontalGroupSection() -> NSCollectionLayoutSection {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1/4))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = .init(top: 3, leading: 3, bottom: 3, trailing: 3)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.9), heightDimension: .fractionalHeight(0.3))
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .groupPaging
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(40))
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)
section.boundarySupplementaryItems = [header]
return section
}
3-3. 세번째 섹션 함수 구현
// 세번째 섹션
private func createThreeHorizontalItemInOneVerticalGroupSection() ->NSCollectionLayoutSection {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = .init(top: 5, leading: 5, bottom: 5, trailing: 5 )
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(0.2))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(40))
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)
section.boundarySupplementaryItems = [header]
return section
}
3-4. 기본 섹션 함수 구현
// 기본 섹션 레이아웃 만들기
private func createDefaultSectionLayout() -> NSCollectionLayoutSection {
// 1. item Size 만들기
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(100))
// 2. item을 만들기
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// 3.Group Size 만들기
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(100))
// 4.group 만들기
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
// 5.section 만들기
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous
return section
}