swiftxcodeuicollectionviewuicollectionviewcellios13.2

iOS - Customisations on my UICollectionViewCell are not applied


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.

Here is what I'm doing

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)
}
}

And here is my Storyboard

Can you explain to me what's wrong with my code ?

My setup :


Solution

  • 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! enter image description here

    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.