UIKit - UICollectionView 개념 및 사용 방법
UIKit - UICollectionView 개념 및 사용 방법
UICollectionView란?
UICollectionView는 UITableView와 비슷하지만 커스텀 레이아웃을 통해 UItableView보다 더 다양한 화면을 구성할 수 있음.
UITableView와 유사하게 셀을 등록해주고, DataSource, Delegate를 통해 셀의 개수, 사용자 동작 처리가 가능함.
차이점으로는 UICollectionView에는 Layout을 반드시 설정해줘야만함.
UITableView와는 달리Layout을 반드시 설정해줘야하며, 설정하지 않을 경우 에러가 발생함.
구현 예시
iTunes Search API를 통해 이미지를 가져와 CollectionView로 표시하는 예시는 아래와 같음.
iTunes Search API Document: link
ViewController.swif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import UIKit
class ViewController: UIViewController {
private let urlSession = URLSession.shared
// CollectionView 셀 수
private let columnCount: CGFloat = 3
// CollectionView 간격 크기
private let columnSpacing: CGFloat = 10
let collectionView: UICollectionView = {
// CollectionView Layout 인스턴스 생성
let layout = UICollectionViewFlowLayout()
// CollectionView 스크롤 방향 설정
layout.scrollDirection = .vertical
return UICollectionView(frame: .zero, collectionViewLayout: layout) // CollectionView 생성
}()
// 데이터 배열
var dataArray: [Software] = []
override func viewDidLoad() {
super.viewDidLoad()
// 초기 데이터 세티
fetchData { result in
switch result{
case .success(let data):
guard let array = data else { return }
self.dataArray = array
print("dataArray count : \(self.dataArray.count)")
DispatchQueue.main.async {
// CollectionView 데이터 로드
self.collectionView.reloadData()
}
case .failure(let error):
print(error.localizedDescription)
}
}
// CollectionView 설정
setupCollectionView()
}
func setupCollectionView(){
// 오토 레이아웃 설정
setupAutoLayout()
// CollectionViewCell 등록
collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: "CustomCollectionViewCell")
// CollectionView DataSource 설정
collectionView.dataSource = self
// CollectionView Delegate 설정
collectionView.delegate = self
}
func setupAutoLayout(){
view.addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
collectionView.topAnchor.constraint(equalTo: view.topAnchor)
])
}
}
// MARK: - CollectionView DataSource
extension ViewController: UICollectionViewDataSource{
// CollectionView 요소 수 반환
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("count : \(dataArray.count)")
return dataArray.count
}
// CollectionView 셀 반환
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionViewCell", for: indexPath)
as! CustomCollectionViewCell
cell.image = dataArray[indexPath.row].imageUrl
return cell
}
// iTunes Search API 호출
func fetchData(completionHandler: @escaping (Result<[Software]?, Error>) -> Void){
let urlStr = "https://itunes.apple.com/search?term=app&media=software"
print("urlStr : \(urlStr)")
guard let url = URL(string: urlStr) else {
print("URL 변환 실패")
return
}
URLSession.shared.dataTask(with: url) { data, _, error in
if error != nil{
print("에러 발생")
completionHandler(.failure(Error.self as! Error))
return
}
guard let data = data else {
print("데이터 요청 실패")
completionHandler(.failure(Error.self as! Error))
return
}
guard let softwareResult = try? JSONDecoder().decode(SoftwareData.self, from: data) else {
print("파싱 실패")
completionHandler(.failure(Error.self as! Error))
return
}
completionHandler(.success(softwareResult.results))
}.resume()
}
}
// MARK: - CollectionView Layout Delegate
extension ViewController: UICollectionViewDelegateFlowLayout{
// Cell 크기 설정
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// 전체 간격 사이즈
let totalSpacing = columnSpacing * (columnCount - 1)
// 간격 사이즈를 제외한 전체 화면 크기
let viewWidth = self.view.frame.width - totalSpacing
// 전체 화면 크기를 한 줄에 들어갈 셀 개수로 나누기 = 셀 하나의 크기
let cellWidth = viewWidth / columnCount
return CGSize(width: cellWidth, height: cellWidth)
}
// Verticle 간격 설정
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return self.columnSpacing
}
// Horizontal 간격 설정
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return self.columnSpacing
}
}
CustomCollectionViewCell.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import UIKit
class CustomCollectionViewCell: UICollectionViewCell {
let imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .black
return imageView
}()
var image: String? {
didSet{
loadImage()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(imageView)
setupAutoLayout()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func setupAutoLayout(){
NSLayoutConstraint.activate([
imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0),
imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0),
imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0),
imageView.topAnchor.constraint(equalTo: self.topAnchor, constant: 0)
])
}
func loadImage(){
guard let urlStr = image, let url = URL(string: urlStr) else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
guard let data = data else { return }
DispatchQueue.main.async {
self.imageView.image = UIImage(data: data)
}
}.resume()
}
}
Software.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Foundation
struct SoftwareData: Codable{
var resultCount: Int
var results: [Software]
}
struct Software: Codable{
var imageUrl: String?
enum CodingKeys: String, CodingKey {
case imageUrl = "artworkUrl100"
}
}
결과
This post is licensed under CC BY 4.0 by the author.
