UICollectionView - Basic반 수업 공부
UICollectionView 란,,!
공식문서 설명 상으로는
정렬된 데이터 항목 컬렉션을 관리하고 사용자 정의 가능한 레이아웃을 사용하여 이를 표시하는 객체라고 되어있다.
@MainActor
class UICollectionView : UIScrollView
UIScrollView를 상속받는다.
컬렉션뷰의 데이터는 개별 항목으로 구성되며, 이를 프레젠테이션을 위해 섹션으로 그룹화 할 수 있다.
항목은 표시하려는 가장 작은 데이터 단위. 예를 들어, 사진앱에서 항목은 단일 이미지 일 수 있다.
컬렉션뷰는 데이터소스가 구성하고 제공하는 클래스의 인스턴스인 셀을 사용하여 화면에 항목을 표시한다. UICollectionViewCell
셀 외에도 컬렉션 뷰는 다른 유형의 뷰를 사용하여 데이터를 표시할 수 있고, 이러한 보충뷰는 예를들어 개별 셀과 분리되어 있지만 여전히 정보를 전달하는 섹션 헤더 및 푸터일 수 있다, 보충뷰에 대한 지원은 선택사항이며 컬렉션 뷰의 레이아웃 개체에 의해 정의되며, 이는 뷰의 배치를 정의하는 역할을 한다.
UICollectionViewDiffableDataSource 개체는 이 프로세스를 자동으로 관리합니다.
사용자 지정 데이터 소스를 사용하는 경우 컬렉션에서 데이터를 추가, 삭제 또는 재정렬할 때마다의 메서드를 사용하여 해당 셀을 삽입, 삭제 및 재정렬합니다.
선택한 항목을 관리하려면 컬렉션 뷰 개체를 사용할 수도 있습니다. 하지만 이 동작의 경우 컬렉션 뷰는 연관된 delegate개체와 함께 작동합니다.
주요 구성 요소
UICollectionView: 컬렉션 뷰 자체를 나타내는 클래스
UICollectionViewCell: 컬렉션 뷰의 각 셀을 나타내는 클래스. 셀은 컬렉션 뷰에 표시되는 단위 요소이다.
UICollectionViewLayout: 컬렉션 뷰의 레이아웃을 정의하는 클래스. 기본적으로 제공되는 'UICollectionViewFlowLayout'을 사용하거나, 사용자 정의 레이아웃을 정의할 수 있다.
UICollectionViewDataSource: 컬렉션 뷰에 데이터를 제공하는 프로토콜이다. 'UITableViewDataSource'와 유사하게, 셀의 개수 및 각 셀의 콘텐츠를 설정하는 역할을 한다.
UICollectionViewDelegate: 셀 선택 등의 상호작용을 처리하는 프로토콜이다.
컬렉션 뷰 만드는 방법~!
뷰 컨트롤러의 뷰에 UICollectionView를 추가하고 적절한 제약조건을 설정해준다.
UICollectionView를 생성하고 화면에 추가하려면, ViewController 클래스 안에서 컬렉션 뷰를 초기화하고 설정해줘야 한다.
import UIKit
class ViewController: UIViewController {
// 1. 컬렉션 뷰 생성
var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// 2. 레이아웃 설정
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 100, height: 100) // 셀 크기 설정
layout.minimumInteritemSpacing = 10 // 셀 간 간격 설정
layout.minimumLineSpacing = 10 // 행 간 간격 설정
// 3. 컬렉션 뷰 초기화
collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
collectionView.backgroundColor = .white // 컬렉션 뷰 배경색 설정
// 4. 데이터 소스 및 델리게이트 설정
collectionView.dataSource = self
collectionView.delegate = self
// 5. 컬렉션 뷰 셀 등록
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
// 6. 컬렉션 뷰를 뷰에 추가
self.view.addSubview(collectionView)
}
}
이렇게 하면 일단 오류가 뜬다
dataSource랑 delegate부분에 ㅎ
fix를 누르면 코드들이 추가되고 오류는 사라지는데
코드 위쪽에 추가가 되고~
그렇게 진행해도 되고 밑에 extension으로 빼서 작성해줘도 되는데
이유는 몰까! 모냐면! 그건 밑에서 다시 할게여,,
그리고 데이터소스 및 델리게이트 설정
컬렉션 뷰가 데이터를 표시할 수 있도록 데이터소스와 델리게이트 메서드를 구현해야 한다.
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
// 섹션당 아이템 수를 반환하는 메서드
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20 // 20개의 셀을 표시
}
// 각 셀을 구성하는 메서드
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.backgroundColor = .blue // 셀 배경색을 파란색으로 설정
return cell
}
// 셀을 선택했을 때 호출되는 메서드 (선택 사항)
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected item at \(indexPath.row)")
}
}
전체적으로 코드를 보면
import UIKit
class ViewController: UIViewController {
// 1. 컬렉션 뷰 생성
var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// 2. 레이아웃 설정
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 100, height: 100)
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
// 3. 컬렉션 뷰 초기화
collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
collectionView.backgroundColor = .white
// 4. 데이터 소스 및 델리게이트 설정
collectionView.dataSource = self
collectionView.delegate = self
// 5. 컬렉션 뷰 셀 등록
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
// 6. 컬렉션 뷰를 뷰에 추가
self.view.addSubview(collectionView)
}
}
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.backgroundColor = .blue
return cell
}
// 콘솔창에 찍는 코드
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected item at \(indexPath.row)")
}
}
extension을 사용해 UICollectionViewDataSource와 UICollectionViewDelegate 메서드를 정의하는 것과, 직접 클래스 내부에서 메서드를 작성하는 것의 차이는 코드의 구조화 방식과 가독성에 있다. 이 둘은 기능적으로 동일하지만, 코드 관리와 확장성 측면에서 차이가 있다.
클래스 내부에 작성하는 경우
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// 컬렉션 뷰 설정 코드
}
// UICollectionViewDataSource 메서드
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.backgroundColor = .blue
return cell
}
// UICollectionViewDelegate 메서드
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected item at \(indexPath.row)")
}
}
모든 코드가 한 곳에 있으므로 작은 프로젝트에서는 이해하기 쉽고 관리가 간편하다.
클래스에 많은 메서드가 추가될 경우, 코드가 길어져 가독성이 떨어질 수 있다.
클래스가 너무 많은 책임을 가지게 되어 응집도가 낮아질 수 있다. 이는 유지보수와 확장에 어려움을 줄 수 있다.
extension을 사용하여 분리하는 경우
class ViewController: UIViewController {
var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// 컬렉션 뷰 설정 코드
}
}
// MARK: - UICollectionViewDataSource
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.backgroundColor = .blue
return cell
}
}
// MARK: - UICollectionViewDelegate
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected item at \(indexPath.row)")
}
}
코드 가독성이 좋아진다. 각 프로토콜에 해당하는 메서드를 별도의 extension으로 분리함으로써 클래스의 본래 역할(즉, 뷰 컨트롤러의 기본로직)을 더 명확하게 할 수 있다.
관리가 용이하다. 프로토콜별로 코드가 분리되므로 특정 기능에 집중하여 코드의 모듈화를 촉진한다.
코드가 더 잘 분리되어 있어 새로운 프로토콜을 구현하거나 기존 프로토콜을 수정할 때 관리가 쉬워 유지보수성이 좋다.
하지만 프로젝트가 작거나 간단한 경우, 코드가 여러곳에 분리되어있어 오히려 코드를 이해하기 어려울 수 있다.
UICollectionView는 기본적으로 수직!으로 정렬된다.
위에서 작성한 코드를 시뮬 돌리면 한 행에 3개의 셀이 들어가고 그 밑으로 정렬이 되는데
UICollectionViewFlowLayout()을 사용해서 이런 화면이 나온것이당!
UICollectionViewFlowLayout이게 제일 많이 사용되는 기본 레이아웃이고
다른 레이아웃을 사용할 수도 있는데
UICollectionViewCompositionalLayout 이 레이아웃을 사용하면 섹션별로 다른 레이아웃을 설정하거나 다양한 형태의 셀 배치를 쉽게 구성할수 있단다!
https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout
UICollectionViewCompositionalLayout | Apple Developer Documentation
A layout object that lets you combine items in highly adaptive and flexible visual arrangements.
developer.apple.com
UICollectionViewCompositionalLayout 에 관련된 공식문서 임당
얘는 iOS 13 부터 도입된 레이아웃 시스템~
다양한 서드파티 라이브러리도 존재한다
예를들어
PinterestLayout: Pinterest 스타일의 그리드 레이아웃을 구현하는 데 사용할 수 있다.
WaterfallLayout: 물이 떨어지는 듯한 배치(Waterfall layout) 스타일을 구현할 수 있다.
이러한 라이브러리들은 특별한 형태의 레이아웃을 더 쉽게 구현할 수 있게 해준다.
휴,, 일단 정리 끝!
사용방법은 더더 연습해봐야 할거 같지만
정리하면서 대충 여태 사용했던 것들이 이해가 갈락말락했고
이제 테이블뷰랑 무슨 차이점이 있는지도 함 찾아서 정리할 예정!
내용의 도움은 공식문서와 지티피요 ㅎㅋ 지씨 고마워~!
https://developer.apple.com/documentation/uikit/uicollectionview
UICollectionView | Apple Developer Documentation
An object that manages an ordered collection of data items and presents them using customizable layouts.
developer.apple.com