⚠️ 읽기 전 참고
본문은 컬렉션 뷰를 구현하는 법에 관한 게시글이 아닌,
구현을 위해 필요한 클래스와 프로토콜에 대해 알아보는 글입니다!
iOS에서 가장 대표적이고 많이 쓰이는 UI 구성 방식은 리스트 형태로 구성된 화면일 것이다.
이를 구현하기 위해서는 UIView들을 나열하거나, UIScrollView 안에 UIStackView를 넣거나, UITableView를 사용하는 방법 등을 이용할 수 있다.
하지만 들어가는 리스트가 격자 형태(Grid)이거나 가로로 스크롤이 필요한 경우가 있다면 상황이 복잡해진다.
이러한 상황들을 포함해서 반복되는 복잡한 UI를 구성하기 위한 방법으로 UICollcetionView를 사용한다.
UICollectionView
- 정의: 유연하게 변경 가능한 레이아웃을 사용하여 특정 타입 형태로 정렬된 데이터 집합을 표시하는 방법
- 특징
- 행과 열의 나열 뿐만이 아닌, 다양한 배열 형태로 구현이 가능하다.
- Grid, Stack, 원, 동적으로 변하는 레이아웃 등
- Data와 해당 Data를 표시하는 데 사용되는 시각적 요소를 엄격하게 구분한다. (= 책임을 분리한다)
- 데이터의 보관과 표시를 별도로 구현한다.
- 뷰들을 배치하고 속성을 지정하는 Layout 객체와 함께 작업을 수행한다.
- 구현
Purpose | Classes / Protocols |
최상위 | - UICollectionView - UICollectionViewController |
데이터 관리 | - UICollectionViewDataSource (Protocol) - UICollectionViewDelegate (Protocol) |
표시 | - UICollectionResuableView - UICollectionViewCell |
레이아웃 | - UICollectionViewLayout - UICollectionViewLayoutAttributes - UICollectionViewUpdateItem |
레이아웃 구성 | - UICollectionViewFlowLayout - UICollectionViewDelegateFlowLayout (Protocol) |
1. UICollectionView, UICollectionViewController
- 시각적인 요소 정의
- UIScollView 상속
- Layout 정보 기반 데이터 표시
- UICollectionViewController는 UICollectionView를 뷰 컨트롤러 수준에서 관리할 수 있도록 해주는 것.
2-1. UICollectionViewDataSource
- 필수 요소
- Content 관리 및 Content 표시에 필요한 View 생성
2-2. UICollectionViewDelegate
- 선택 요소
- 특정 상황에서 View가 동작하도록 custom.
3. UICollectionViewReusableView, UICollectionViewCell
- 각각의 item, Header, Footer 등
- 재사용 가능
- UICollectionView에 표시되는 모든 뷰들은 UICollectionViewReusableView의 인스턴스.
- 왜냐면 컬렉션뷰 → 스크롤 → 안 보였던 내용들을 보여주기 위해 재사용 메커니즘을 사용하니까
- 레이아웃 표현 시 contentView에 적용한다.
- contentView라는 기본 객체가 superView가 되고, 그 위에 서브 뷰(= cell)들을 올리는 것이다.
4. UICollectionViewLayout, UICollectionViewLayoutAttributes, UICollectionViewUpdateItem
- 각 항목의 배치와 같은 시각적 스타일을 담당
- View를 직접 소유하지 않는 대신 Attributes를 생성
- 컬렉션 뷰가 적용할 수 있도록 속성만 알려준다는 소리임
- 데이터 항목 수정 시 UpdateItem 인스턴스를 수신
- ex - 삽입, 삭제, 이동 등
- 코드 예시
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
super.preferredLayoutAttributesFitting(layoutAttributes)
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var frame = layoutAttributes.frame
frame.size.height = ceil(size.height)
layoutAttributes.frame = frame
return layoutAttributes
}
5. UICollectionViewFlowLayout, UICollectionViewDelegateFlowLayout
- Grid, lind-based 레이아웃을 구현하거나, 레이아웃 정보를 동적으로 custom 하는 데 사용
- 적용
- FlowLayout 객체 생성 → CollectionView에 할당
- 셀 너비, 높이 설정
- 스크롤 방향 설정 (기본값 = vertical)
- 선택 사항
- items, lines 간격
- Header, Footer의 사이즈 명시
- 코드 예시
let pillInfoCollectionView = UICollectionView(frame: .zero, collectionViewLayout: .init()).then {
let layout = UICollectionViewFlowLayout()
layout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.size.width - 40, height: 166)
layout.footerReferenceSize = CGSize(width: UIScreen.main.bounds.size.width - 40, height: 132)
layout.headerReferenceSize = CGSize(width: UIScreen.main.bounds.size.width - 40, height: 48)
layout.minimumInteritemSpacing = 11
layout.sectionInset = UIEdgeInsets(top: 11, left: 0, bottom: 16, right: 0)
layout.scrollDirection = .vertical
$0.backgroundColor = .clear
$0.collectionViewLayout = layout
$0.register(PillInfoCollectionViewCell.self)
$0.register(PillInfoHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: PillInfoHeaderView.reuseIdentifier)
$0.register(PillInfoFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: PillInfoFooterView.reuseIdentifier)
$0.showsVerticalScrollIndicator = false
}
👀 정리
참고
- About iOS Collection Views
- UICollectionView
- UICollectionViewFlowLayout
👻 이어지는 게시글 - UICollectionViewCompositionalLayout (작성 예정 ...)
'개발 > iOS' 카테고리의 다른 글
[iOS] iOS는 어떻게 이루어져 있을까? (0) | 2022.03.19 |
---|---|
[iOS] UDID (Unique Device Identifier) (2) | 2022.03.16 |
[Swift] ARC, Retain Cycle, weak, unowned (2) | 2022.02.22 |
[iOS] CollectionView의 extension으로 EmptyView 만들기 (0) | 2022.02.19 |
[iOS] loadView() 오류: Could not load NIB in bundle '~ (loaded)' with name '~ViewController' (0) | 2022.02.17 |
댓글