-
UICollectionView Compositional LayoutiOS/Swift 2022. 2. 17. 00:48
안녕하세요!! 오늘은 UIColletionView의 Layout중 하나인 Compositional Layout에 대해서 정리해보았습니다.
바로 시작하겠습니다 🐶
UICollectionView CompositionalLayout이란?
iOS 13.0 이상부터 사용 가능한 컬렉션 뷰 레이아웃의 한 종류로,
UICollectionViewLayout을 상속받아 만들어져있다.
CollectionView의 레이아웃을 쉽게 커스터마이징 할 수 있는 옵션을 제공해준다.
이름처럼 여러가지 컴포넌트들로 이루어져 있는데,
다음과 같이 섹션, 그룹, 아이템으로 나누어져 있다.
왜 사용하게 되었나
기존에 사용하던 Flowlayout의 한계를 느껴서 사용하게 됐다.
다음과 같이 태그 컬렉션 뷰를 구현해야 했는데, 처음에는 UICollectionView Flowlayout으로 구성했다.
그리고 완성된 결과물이 이것이었는데,
Flowlayout은 minimum spacing에 대한 값만 받는다.
즉, 고정된 Spacing 값을 줄 수 없다보니 item들이 중구난방으로 띄워져있었다..😞
고정된 Spacing을 어떻게 줄까 하면서 구글링을 해봤는데, 그때 CompositionalLayout을 알게되었다!
사용법
사용법은 간단하다.
1. item의 사이즈를 정한다.
let itemSize = NSCollectionLayoutSize( widthDimension: .estimated(70), heightDimension: .estimated(32) )
다음과 같은 방법으로 사이즈를 만들 수 있다.
widthDimension에는 너비값, heightDimension에는 높이값을 넣으면 된다.
사이즈를 정하는 방법에도 여러가지 방법이 있는데,
absolute: 고정된 값을 넣을 때
estimated: contentsSize값으로 결정하고 싶을 때. Content Size와 비슷한 값으로 설정해야 성능이 좋아진다.
fractional: 슈퍼뷰의 비율에 맞게 결정하고 싶을 때 (0.0 ~ 1.0 사이의 값)
이 세가지 방법으로 사이즈를 알맞게 정해주면 된다.
2. item 객체를 만든다.
let item = NSCollectionLayoutItem(layoutSize: itemSize)
위에서 만든 사이즈 객체를 토대로 아이템 객체를 만들어준다. 이것이 하나의 Cell이 된다.
3. Group 사이즈를 정한다.
let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(100) )
Cell들의 한 집합인 Group의 사이즈를 정해준다.
까만색 네모로 묶은 부분이 그룹이 되는 부분이다.
Group 객체를 만들 때 어떤 기준으로 그룹을 설정할 지 결정할 수 있다.
4. Group 객체를 만든다.
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
위에서 만들어둔 그룹 사이즈 객체와 아이템 객체로 생성할 수 있다.
그룹은 vertical과 horizontal을 기준으로 만들 수 있고, 커스텀으로도 만들 수 있다.
원하는 방식으로 만들어주면 된다.
그룹을 만들 수 있는 생성자들 또한, 그룹에서는 아이템들 간의 간격(Spacing)을 설정 가능하다.
group.interItemSpacing = NSCollectionLayoutSpacing.fixed(8)
fixed로 고정된 spacing 값을 줄 수 있고, flexible로 유연한 spacing값을 줄 수도 있다.
5. Section 객체를 만든다.
let section = NSCollectionLayoutSection(group: group)
section에서는 그룹들간의 간격, 그리고 섹션의 contents inset 또한 설정 가능하다.
section.contentInsets = NSDirectionalEdgeInsets(top: 16 + sectionHeaderPadding, leading: 16, bottom: 8, trailing: 16) section.interGroupSpacing = 12
이 외에도, 섹션의 헤더 뷰, 푸터 뷰 또한 설정할 수 있다.
boundarySupplementaryItems 속성을 이용하면 된다.
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(18)), elementKind: UICollectionView.elementKindSectionHeader, alignment: .topLeading, absoluteOffset: CGPoint(x: 0, y: sectionHeaderPadding)) section.boundarySupplementaryItems = [header]
NSCollectionLayoutBoundarySupplementaryItem을 만들 때에는,
layoutSize → 헤더뷰나 푸터뷰의 사이즈
elementKind → 헤더뷰나 푸터뷰의 종류
alignment → 정렬하는 지점
이 세가지를 넣어주면 된다. 그리고 absoluteOffset나 constraints로 헤더뷰가 시작하는 위치를 조절할 수 있다.
6. UICollectionViewCompositionalLayout 객체를 만든다.
let layout = UICollectionViewCompositionalLayout(section: section)
전체 코드
extension UICollectionViewLayout { static func fixedSpacedFlowLayout() -> UICollectionViewLayout { let itemSize = NSCollectionLayoutSize( widthDimension: .estimated(70), heightDimension: .estimated(32) ) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(100) ) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) group.interItemSpacing = NSCollectionLayoutSpacing.fixed(8) let section = NSCollectionLayoutSection(group: group) let sectionHeaderPadding: CGFloat = 32 section.contentInsets = NSDirectionalEdgeInsets(top: 16 + sectionHeaderPadding, leading: 16, bottom: 8, trailing: 16) section.interGroupSpacing = 12 let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(18)), elementKind: UICollectionView.elementKindSectionHeader, alignment: .topLeading, absoluteOffset: CGPoint(x: 0, y: sectionHeaderPadding)) section.boundarySupplementaryItems = [header] let layout = UICollectionViewCompositionalLayout(section: section) return layout } }
같은 UI를 사용할 것 같은 포인트가 있어 extension으로 따로 함수를 작성해두었다.
시뮬레이터를 켜서 레이아웃을 확인해보면,
원하는대로 UI가 잘 잡힌 것을 확인할 수 있다!!!
'iOS > Swift' 카테고리의 다른 글
SwiftUI 제스처가 작동하지 않을 때 (0) 2022.07.10 (RxSwift)API 호출 시점이 많을 때, 효율적으로 관리하기 (0) 2022.02.23 RxDataSources + 컬렉션 뷰(Swift) (0) 2022.02.16 Firebase Auth 적용하기(전화번호 인증, Swift) (0) 2022.02.04 앱에 Firebase Crashlytics 추가(Swift) (0) 2022.01.27