UICollectionView is such an important UI component which has been used very often in iOS app. It's used to show collection of items in a defined layout.
UICollectionView comes with some protocols that we need to conform correctly in order to display data. And yet no matter how many times I need it, I had to go back, search for some old setup, gathering pieces of the puzzle then try to glue them together, again and again.
And today is the day I tell myself to note it down, for my future absent-mind me.
I myself am more familiar with implementing UI elements programmatically, so in this tutorial, I will:
- Create a "Screen" which extends
UIViewController
, because the UICollectionView is not the only element in the screen, you might want to add UILabel to the top, or other component to the bottom, we'll start with aUIViewController
as a blank canvas - Programmatically add a
UICollectionView
component to the screen - Create a custom Cell that extends
UICollectionViewCell
then use it in theUICollectionView
The final code look like this:
// file CollectionCell.swift
class CollectionCell: UICollectionViewCell {
var imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.isUserInteractionEnabled = true
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: Helper
extension CollectionCell {
fileprivate func setup() {
self.addSubview(imageView)
imageView.anchor(top: self.topAnchor, left: self.leftAnchor,
bottom: nil, right: nil,
paddingTop: 0, paddingLeft: 0,
paddingBottom: 0, paddingRight: 0,
width: 0, height: 0)
}
}
// file HomeViewController.swift
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
lazy var cv: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
return cv
}()
// Mock data
let collections: [Collection] = [
Collection(name: "Animals"),
Collection(name: "Emotions"),
Collection(name: "Tools")
]
}
// MARK: - Lifecyle
extension HomeViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Add other elements of the screen, in this case, the UICollectionView
setupSubViews()
}
}
// MARK: Helpers
extension HomeViewController {
fileprivate func setupSubViews() {
view.backgroundColor = UIColor.white
view.addSubview(cv)
cv.register(CollectionCell.self, forCellWithReuseIdentifier: cellId)
cv.dataSource = self
cv.delegate = self
cv.anchor(top: view.bottomAnchor, left: view.leftAnchor,
bottom: view.bottomAnchor, right: view.rightAnchor,
paddingTop: 8, paddingLeft: 8,
paddingBottom: 8, paddingRight: 8,
width: 0, height: 0)
}
}
// MARK: UICollectionViewDataSource
extension HomeViewController {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return collections.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CollectionCell
let collection = collections[indexPath.row]
cell.imageView.image = UIImage.init(named: collection.getImage())
return cell
}
}