In an application I'm trying to build I need a lot of UICollectionView
s (around 10). I decided to make the collectionView
s without the use of Storyboards (i.e entirely in code) . Storyboards complicate things(for many collectionViews) .
Here is the code:
I)
override func viewDidLoad() {
super.viewDidLoad()
//Create the collection View
let frame = CGRect(origin: CGPoint.zero , size: CGSize(width: self.view.frame.width , height: 50))
let layout = UICollectionViewFlowLayout()
collectionView1 = UICollectionView(frame: frame, collectionViewLayout: layout)
collectionView1.dataSource = self
collectionView1.delegate = self
collectionView1.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellIdentifier")
collectionView1.backgroundColor = UIColor.red
view.addSubview(collectionView1) }
II)
// TheData Source and Delegate
extension ViewController : UICollectionViewDataSource , UICollectionViewDelegateFlowLayout{
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellIdentifier", for: indexPath)
cell.backgroundColor = UIColor.darkGray
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 50, height: 50)
}
}
This would create one collectionView
in a View Controller , however if I had to create ten more of these I would have to rewrite the above code 10 times .
So I tried to create a separate MyCollectionView
class with the basic implementation needed to add a collectionView
to a ViewController
so that
all I had to do in my view controller was something as simple as
override func viewDidLoad() {
super.viewDidLoad()
let shoesCollection = MYCollectionView(frame : ...)
self.view.addSubview(shoesCollection)
let foodCollection = MYCollectionView(frame : ...)
self.view.addSubview(foodCollection)
let carCollection = MYCollectionView(frame : ...)
self.view.addSubview(carCollection)
}
or something similar . However I was unsuccessful. How shall I go about this? Thanks!
I will just give you simple example although I'm not sure if this is what you wanted. Again, it totally depends on the design you are implementing but this could be one of the ideas.
The idea is
Create a collection view that will populate 10 collection views you want to add.
Create a collection view cell that has the collection view you want to repeat.
Feed different data(food, shoes, cars and so on) to the collection view cell (MYCollectionView).
Feed each data to the collection view in the cell to populate the individual data.
ViewController
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 10
layout.scrollDirection = .vertical
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(MYCollectionView.self, forCellWithReuseIdentifier: NSStringFromClass(MYCollectionView.self))
collectionView.backgroundColor = .clear
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
collectionView.frame = view.bounds
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(MYCollectionView.self), for: indexPath) as! MYCollectionView
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.bounds.width, height: 100)
}
}
MYViewController
class MYCollectionView: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellIdentifier")
collectionView.backgroundColor = UIColor.red
return collectionView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(collectionView)
}
override func layoutSubviews() {
super.layoutSubviews()
collectionView.frame = bounds
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 15
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellIdentifier", for: indexPath)
cell.backgroundColor = UIColor.darkGray
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: bounds.height, height: bounds.height)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Clicked")
}
}
Updated: Since the question was only about reusing collection view I didn't really pass the data all the way to the reused collection views. Assuming that when the view controller is loaded you have the data, let say array of shoes, food and cars and also each array components are array too.
For example,
let shoes = [...] //array of shoes
let foods = [...] //array of foods
let cars = [...] //array of cars
let data = [shoes, foods, cars]
Now your data array has 3 components and this will decide number of the collection view you created in your question. So in the view controller in my example code,
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(MYCollectionView.self), for: indexPath) as! MYCollectionView
let components = data[indexPath.item]
cell.data = components
return cell
}
In MYCollectionView, you should have a variable, data.
var data:[WhateverYourDataModel] = [] {
didSet {
collectionView.releadData()
}
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellIdentifier", for: indexPath)
cell.backgroundColor = UIColor.darkGray
//let component = data[indexPath.item]
//You should create a custom collection view cell to display whatever you want to display with the data, component.
return cell
}
To make it clean, your data object should have common base model so you can pass them from view controller all the way down to the collection view in the MYCollectionView.