앱 화면에 여러 개의 상자를 가지런히 보여주는 도구
이 상자 안에는 사진, 글자, 버튼 등 네가 원하는 걸 넣을 수 있음
ex)
사진 앨범처럼 여러 장의 사진을 줄 맞춰서 보여줄 때
카드 뉴스처럼 옆으로 넘기는 카드들을 만들고 싶을 때
| 비교 항목 | UITableView (테이블뷰) | UICollectionView (컬렉션뷰) |
|---|---|---|
| 모양 | 세로로 한 줄씩 내려가는 리스트 | 가로, 세로, 격자 등 다양하게 배치 가능 |
| 쓰는 곳 | 채팅, 뉴스 목록 등 | 사진첩, 카드 슬라이드, 게임 캐릭터 선택 화면 등 |
요약 )
테이블 뷰는 줄 세우기만 잘함
컬렉션 뷰는 배줄도 세우고, 칸도 나누고, 옆으로 넘기기도 잘함
컬렉션 뷰를 만들기 위해 필요한 것들
ex) 사진 10장을 보여줘, 그림 카드 5개 있어요 이런 거 알려줘야 함
몇 개의 아이템(상자)을 보여줄지
각각 상자 안에 뭐 넣을지 정해주는 것
ex) 이 상자는 사진을 넣을 상자임. 하고 미리 만들어두는 것
이걸 해야 앱이 이 상자를 써야 되는구나 하고 알아차릴 수 있음
ex) 상자를 10/10 크기로 만들고, 옆으로 10씩 띄워주셈 같은 걸 정하는 것
레이아웃은 상자들을 어떻게 정렬할지 알려주는 설계도? 같은 역할
사진첩 앱
가로로 쭉 이어진 아이템
드래그해서 정렬 바꾸는 화면
UICollectionView 안에 줄지어 있는 작은 상자
(직접 디자인 가능)
| 항목 | UITableView | UICollectionView |
|---|---|---|
| 기본 방향 | 세로 리스트 | 그리드, 가로/세로/자유 레이아웃 |
| 셀 배치 | 섹션당 1열 | 여러 열, 자유로운 배치 |
| 셀 크기 | delegate로 조절 가능 | 자유롭게 조정 가능 |
| 커스터마이징 | 단순한 구조 | 매우 유연, 복잡한 레이아웃 가능 |
| 레이아웃 클래스 | 기본 고정 | UICollectionViewLayout으로 직접 정의 |
| 예시 채팅, 뉴스피드, 연락처 | 사진첩, 카드 UI, 쇼핑몰 상품 목록 |
UITableView 사용 추천
세로 리스트
단순 데이터
채팅, 연락처, 뉴스 리스트
UICollectionView 사용 추천
그리드 || 가로/세로 조합 레이아웃
복잡한 셀 배치
사진 앨범, 넷플릭스 UI, 카드 스타일
class MyCollectionViewCell: UICollectionViewCell {
let titleLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.textAlignment = .center
contentView.addSubview(titleLabel)
NSLayoutConstraint.activate([
titleLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor)
])
contentView.backgroundColor = .systemGray5
contentView.layer.cornerRadius = 8
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class MyCollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var items = ["하나", "둘", "셋", "넷", "다섯"]
var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
// 1. 레이아웃 정의
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 100, height: 100)
layout.minimumLineSpacing = 16
layout.minimumInteritemSpacing = 16
layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
// 2. 컬렉션 뷰 생성
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.backgroundColor = .white
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(MyCollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
view.addSubview(collectionView)
}
// 3. 셀 개수 정의
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
// 4. 셀 구성
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? MyCollectionViewCell else {
return UICollectionViewCell()
}
cell.titleLabel.text = items[indexPath.item]
return cell
}
}
| 용어 | 설명 |
|---|---|
| UICollectionViewCell | 각각의 셀 (아이템) |
| UICollectionViewFlowLayout | 셀 배치 방식 결정 |
| register | 셀 클래스 등록 |
| dequeueReusableCell | 셀 재사용 |
| contentView | 셀 내부 뷰 추가 위치 |
| 항목 | 기능 |
|---|---|
| UICollectionViewFlowLayout | 기본 레이아웃 구성 클래스 |
| itemSize | 셀 크기 고정 설정 |
| minimumLineSpacing / minimumInteritemSpacing | 셀 간격 설정 |
| sectionInset | 섹션 주변 여백 |
| scrollDirection | 스크롤 방향 (세로/가로) 설정 |
| UICollectionViewDelegateFlowLayout | 셀 크기를 indexPath마다 동적으로 지정 가능 |
| sizeForItemAt | 셀 크기 동적 계산 구현 메서드 |
| 상황 | 적용 방법 |
|---|---|
| 모든 셀 크기가 동일해야 할 때 | layout.itemSize 사용 |
| 셀 크기를 내용에 따라 다르게 하고 싶을 때 | sizeForItemAt에서 동적 계산 |
| 반응형 셀 배치를 원할 때 (2~3열) | 컬렉션 뷰 너비 기준으로 셀 너비 계산 |
| 텍스트 길이에 맞춘 셀 크기 | NSString.size(withAttributes:) 사용 |
| 커스텀 셀의 내부 뷰 크기에 따라 자동 크기 | preferredLayoutAttributesFitting(_:) 오버라이드 |
| 단계 | 내용 |
|---|---|
| 1️⃣ 셀 클래스 생성 | UICollectionViewCell을 상속받고 UIImageView, UILabel 같은 UI 요소 추가 |
| 2️⃣ UI 설정 | setupUI() 메서드에서 addSubview + NSLayoutConstraint로 오토레이아웃 설정 |
| 3️⃣ 셀 등록 | collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell") |
| 4️⃣ 데이터 바인딩 | cellForItemAt에서 imageView.image와 titleLabel.text 설정 |
| 5️⃣ 모델 구조체 | struct Item { let title: String; let imageName: String } 등으로 데이터 구성 |
contentMode = .scaleAspectFill, layer.cornerRadius, shadow 등으로 디자인 개선 가능
셀 레이아웃은 꼭 오토레이아웃으로 설정해야 스크롤 성능 저하 없이 잘 작동함
| 단계 | 내용 |
|---|---|
| 1️⃣ 뷰 추가 | UIScrollView > UIView 구조로 구성 (스크롤뷰 안에 콘텐츠 뷰) |
| 2️⃣ 오토레이아웃 | scrollView는 view에, contentView는 scrollView.contentLayoutGuide에 맞춤 |
| 3️⃣ 콘텐츠 너비 고정 | contentView.widthAnchor = scrollView.frameLayoutGuide.widthAnchor |
| 4️⃣ 요소 추가 | contentView에 원하는 UI 요소 추가 후 제약 설정 |
| 5️⃣ 높이 중요 | 콘텐츠 높이가 scrollView보다 커야 실제 스크롤 작동함 |
UIScrollView 안에서 스크롤이 안 되는 경우는 대부분 오토레이아웃이 빠졌거나,
콘텐츠 높이가 부족한 경우
view (UIViewController의 기본 뷰)
└── scrollView (UIScrollView)
└── contentView (UIView)
└── [여기에 여러 UI 요소 배치]
화면보다 큰 콘텐츠가 있을 경우 자동 스크롤이 가능하게 됨
class ScrollExampleViewController: UIViewController {
let scrollView = UIScrollView()
let contentView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupScrollView()
setupContent()
setupLayout()
}
private func setupScrollView() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
private func setupContent() {
contentView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentView)
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
// 수평 스크롤 방지
contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
])
}
private func setupLayout() {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.text = Array(repeating: "스크롤 가능한 텍스트입니다.", count: 50).joined(separator: "\n")
contentView.addSubview(label)
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20)
])
}
}
| 대상 | 제약 조건 설명 |
|---|---|
| scrollView → view | 화면에 꽉 차도록 top, leading, trailing, bottom 제약 |
| contentView → scrollView.contentLayoutGuide | 콘텐츠 전체 높이 기준으로 스크롤 영역 설정 |
| contentView.widthAnchor → scrollView.frameLayoutGuide.widthAnchor | 수평 스크롤 방지 (세로 스크롤만 가능) |
| 내부 요소 → contentView | 오토레이아웃으로 콘텐츠 배치 (예: UILabel 등) |
다짐을 남기는 앱을 만들기 위해 Figma를 이용하여 디자인을 하였음 !


거의 60% 완료하였음... 근데 구현하는 게 생각보다 빡세서 좀 더 해봐야할 것 같다!