I'm programming an iOS application using multiple horizontal UICollectionViews stacked in a StackLayout inside a ScrollView. I want to display imaged in theses collection views but my custom UICollectionViewCell is not showing anything.
I've followed this tutorial for the multiple collection views, and this one for the custom cell.
Here is my ViewController :
import UIKit
struct CustomImage {
var title: String
var image: UIImage
}
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
@IBOutlet weak var perspectiveCV: UICollectionView!
@IBOutlet weak var monkeyCV: UICollectionView!
@IBOutlet weak var beachCV: UICollectionView!
let perspectiveImages = [
CustomImage(title: "Perspective 1", image: #imageLiteral(resourceName: "perspective-1")),
CustomImage(title: "Perspective 2", image: #imageLiteral(resourceName: "perspective-2")),
CustomImage(title: "Perspective 3", image: #imageLiteral(resourceName: "perspective-3")),
CustomImage(title: "Perspective 4", image: #imageLiteral(resourceName: "perspective-4")),
CustomImage(title: "Perspective 5", image: #imageLiteral(resourceName: "perspective-5")),
CustomImage(title: "Perspective 6", image: #imageLiteral(resourceName: "perspective-6"))
]
let monkeyImages = [
CustomImage(title: "Monkey 1", image: #imageLiteral(resourceName: "monkey-1")),
CustomImage(title: "Monkey 1", image: #imageLiteral(resourceName: "monkey-2")),
CustomImage(title: "Monkey 1", image: #imageLiteral(resourceName: "monkey-3"))
]
let beachImages = [
CustomImage(title: "Beach 1", image: #imageLiteral(resourceName: "beach-1")),
CustomImage(title: "Beach 2", image: #imageLiteral(resourceName: "beach-2")),
CustomImage(title: "Beach 3", image: #imageLiteral(resourceName: "beach-3")),
CustomImage(title: "Beach 4", image: #imageLiteral(resourceName: "beach-4"))
]
override func viewDidLoad() {
super.viewDidLoad()
title = "Images"
setupCollectionViews()
}
fileprivate func setupCollectionViews() {
// Heights
perspectiveCV.heightAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8).isActive = true
monkeyCV.heightAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8).isActive = true
beachCV.heightAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8).isActive = true
// Left and right padding
perspectiveCV.contentInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
monkeyCV.contentInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
beachCV.contentInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
// Hide scrolling indicator
perspectiveCV.showsHorizontalScrollIndicator = false
monkeyCV.showsHorizontalScrollIndicator = false
beachCV.showsHorizontalScrollIndicator = false
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch collectionView {
case monkeyCV:
return monkeyImages.count
case beachCV:
return beachImages.count
default:
return perspectiveImages.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch collectionView {
case monkeyCV:
let monkeyCell = monkeyCV.dequeueReusableCell(withReuseIdentifier: "monkeyCell", for: indexPath) as! ImageCollectionViewCell
monkeyCell.backgroundColor = UIColor.systemOrange
monkeyCell.data = monkeyImages[indexPath.row]
return monkeyCell
case beachCV:
let beachCell = beachCV.dequeueReusableCell(withReuseIdentifier: "beachCell", for: indexPath) as! ImageCollectionViewCell
beachCell.backgroundColor = UIColor.systemBlue
beachCell.data = beachImages[indexPath.row]
return beachCell
default:
let perspectiveCell = perspectiveCV.dequeueReusableCell(withReuseIdentifier: "perspectiveCell", for: indexPath) as! ImageCollectionViewCell
perspectiveCell.backgroundColor = UIColor.systemRed
perspectiveCell.data = perspectiveImages[indexPath.row]
return perspectiveCell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width * 0.8, height: collectionView.frame.width * 0.8)
}
}
Here is my custom UICollectionViewCell :
import UIKit
class ImageCollectionViewCell: UICollectionViewCell {
var data: CustomImage? {
didSet {
guard let data = data else { return }
bg.image = data.image
}
}
fileprivate let bg: UIImageView = {
let iv = UIImageView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.contentMode = .scaleAspectFit
iv.clipsToBounds = true
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
bg.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
bg.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
bg.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
bg.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
contentView.addSubview(bg)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
Can you explain to me what's wrong with my code ?
My setup :
It looks like you have not established the delegates/datasources assigned to each of your collection views.
In your view did load connect the delegate and datasource to each of your collection views.
self.mycollectionView1.delegate = self
self.mycollectionView1.datasource = self
self.mycollectionView2.delegate = self
self.mycollectionView2.datasource = self
self.mycollectionView3.delegate = self
self.mycollectionView3.datasource = self
You can also set the delegates and datasources through the storyboard. You can select each collectionView and ctrl + drag to your ViewController NOT THE VIEW!
Note the highlighted portion in the image above. That indicates your viewController. Ctrl + drag each collection view to that point and click on delegate and datasource
EDIT-----
Instead of using a switch statement like you have done so here
switch collectionView {
case monkeyCV:
let monkeyCell = monkeyCV.dequeueReusableCell(withReuseIdentifier: "monkeyCell", for: indexPath) as! ImageCollectionViewCell
monkeyCell.backgroundColor = UIColor.systemOrange
monkeyCell.data = monkeyImages[indexPath.row]
return monkeyCell
case beachCV:
let beachCell = beachCV.dequeueReusableCell(withReuseIdentifier: "beachCell", for: indexPath) as! ImageCollectionViewCell
beachCell.backgroundColor = UIColor.systemBlue
beachCell.data = beachImages[indexPath.row]
return beachCell
default:
let perspectiveCell = perspectiveCV.dequeueReusableCell(withReuseIdentifier: "perspectiveCell", for: indexPath) as! ImageCollectionViewCell
perspectiveCell.backgroundColor = UIColor.systemRed
perspectiveCell.data = perspectiveImages[indexPath.row]
return perspectiveCell
}
Try establishing your cells like so
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)-> UICollectionViewCell {
let cell = myCollectionView1.dequeueResuableCell(withReuseIdentifier: "myIdentifier", for: indexPath) as! mycustomCellClass
cell.backgroundColor = UIColor.systemOrange
return cell
if collectionView == mycollectionView2 {
let cell2 = mycollectionView2.dequeueResuableCell(withReuseIdentifier: "myIdentifier2", for: indexPath) as! mycustomCellClass
cell2.backgroundColor = UIColor.systemBlue
}
}
And so on. You may also need to modify your numberOfItemsInSection Function to replace that switch statement as well.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch collectionView {
case monkeyCV:
return monkeyImages.count
case beachCV:
return beachImages.count
default:
return perspectiveImages.count
}
}
From above change it to below
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (collectionView == mycollectionView1 {
return monkeyImages.count
} else if (collectionView == myCollectionView2 {
return beachImages.count
} else {
//this is your final collectionview
return persepctiveImages.count
}
}
EDIT 2-----------
Try removing the sizeForItemAt
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width * 0.8, height: collectionView.frame.width * 0.8)
}
Go to your storyboard and physically drag the size you want the cell to be. On the right panel inside the size inspector, make sure the 'Estimate Size' option is set to none.
Also you can try this as well.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (collectionView.frame.size.width/3), height: collectionView.frame.size.height)
}
Dividing by 3 gives three cells.