CollectionView sizeForItemAtIndexPath never called

Ios

Ios Problem Overview


This is driving me crazy! I have a UICollectionViewController as shown below:

class PhrasesCompactCollectionViewController: UICollectionViewController

The numberOfSections and cellForItemAt are being called but the sizeForItemAtIndexPath is never called. I am using the same exact code somewhere else and it fires correctly. I am using Xcode 8 Beta 6.

func collectionView(collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAtIndexPath indexPath:  NSIndexPath) -> CGSize {
        
        return CGSize(width: 120, height:120) 
    }

Ios Solutions


Solution 1 - Ios

You need to specify that you implement the protocol UICollectionViewDelegateFlowLayout in your class declaration.

Solution 2 - Ios

I had the same problem. The one thing that helped me was to make the 'Estimated Size' for the Cell Size under the collectionView size inspector 'None'.

enter image description here

Solution 3 - Ios

In Swift 3+ Use this method:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width:(collectionView.frame.height-90)/2, height: 100)
}

Make sure that your class complies both Delegate

  • UICollectionViewDelegate

  • UICollectionViewDelegateFlowLayout

Solution 4 - Ios

Swift 5

All these steps are required :

  1. Conform to UICollectionViewDelegateFlowLayout <== Absolutely needed !!
  2. and to UICollectionViewDelegate, UICollectionViewDataSource
  3. Set these in viewDidLoad : collectionView.delegate = self and collectionView.dataSource = self
  4. Set Estimate Size to None in the Interface Builder
  5. Make sure the following method has sizeForItemAt and not sizeForItemAtIndexPath

as :

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
    return CGSize(width: 100, height:100)
} 

Solution 5 - Ios

Swift 3

To set Cell Size of UICollectionView, you need to create and customise object of UICollectionViewFlowLayout. Customise the properties and set that layout object to the UICollectionView object.

Change cellheight and cell cellWidth objects according to your requirement (the cell hight and width you want).

override func viewDidLoad() {
    super.viewDidLoad()
    
    let cellWidth : CGFloat = myCollectionView.frame.size.width / 4.0
    let cellheight : CGFloat = myCollectionView.frame.size.height - 2.0
    let cellSize = CGSize(width: cellWidth , height:cellheight)
    
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .vertical //.horizontal
    layout.itemSize = cellSize
    layout.sectionInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
    layout.minimumLineSpacing = 1.0
    layout.minimumInteritemSpacing = 1.0
    myCollectionView.setCollectionViewLayout(layout, animated: true)
    
    myCollectionView.reloadData()
}

Make Sure: if you added sizeForItemAt indexPath method then must REMOVE the method...

> Remove Below Method

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

}

Solution 6 - Ios

First class need to confirm to UICollectionViewDelegateFlowLayout. Then you need to write following code in viewDidLoad():

//To tell the UICollectionView to use your UIViewController's UICollectionViewDelegateFlowLayout methods

collectionView.delegate = self

// If you want to set your own collection view flow layout

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical //depending upon direction of collection view

self.collectionView?.setCollectionViewLayout(layout, animated: true)

By using this code UICollectionViewDelegateFlowLayout method

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize

will get called, you can set size in this method.

Solution 7 - Ios

Three things you need to check if no answer works:

  1. Implement FlowLayout Delegate : class MyController: UICollectionViewController, UICollectionViewDelegateFlowLayout

  2. Use method for size of item for swift 3.0+: func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: (collectionView.frame.width / 3) - 1, height: collectionView.frame.width) }

  3. Select Estimate size = None in Inspect element of UICollectionView.

Solution 8 - Ios

Make sure you put this in viewDidLoad()

collectionView.delegate = self

Solution 9 - Ios

I had the same problem and nothing would fix it. I had a yellow warning saying to make it private because it came close to another function defined by the Layout Delegate. What fixed it for me was:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize

Notice the difference from "sizeForItemAtIndexPath" to the correct "sizeForItemAt".

I tore my hair out for days trying to figure this out and it finally worked. Below I will include all of my function to show you how I also "hid" a cell by making the height equal to 0.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let findIndex = labelArray.index(of: "\(labelArray[indexPath.row])")
    let screenSize = UIScreen.main.bounds
    let screenWidth = screenSize.width
    
    if (findIndex! % 2 == 0){
        // Even index, show cell
        return CGSize(width: screenWidth, height: 246)
    }
    else {
        return CGSize(width: screenWidth, height: 0)
    }
}

Solution 10 - Ios

Just add: UICollectionViewDelegateFlowLayout

class YourClass: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {}

Solution 11 - Ios

may you set the wrong layout: UICollectionViewLayout, actually this layout should be UICollectionViewFlowLayout this like

Solution 12 - Ios

I had this issue last night. Finally solved it at midnight when I realised 'didSelectItemAtIndex' method was not closed off with a closure bracket "}"

I added a closure bracket at the very bottom of the class when asked by the compile error. So in effect all the methods below 'didSelectItemAtIndex' were inside that method.

Posting here just in case anyone else wastes 4 hours of their evenings on this one :-(

Solution 13 - Ios

Use this method

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    
}

Instead of

private func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    
}

Solution 14 - Ios

Don't forget to use UICollectionViewDelegateFlowLayout. Set the spacings in xib/storyboard and resize the cell with below updated function for newer Swift versions. Happy coding !!

   @objc(collectionView:layout:sizeForItemAtIndexPath:)
func collectionView(_ collectionView: UICollectionView,
                    layout collectionViewLayout: UICollectionViewLayout,
                    sizeForItemAt indexPath: IndexPath) -> CGSize {
    let numberOfItemsPerRow:CGFloat = 5
    
    if let collection = self.collectionView {
        let width = collection.bounds.width / numberOfItemsPerRow
        
        return CGSize(width: width, height: 36)
    }else{
        return CGSize(width: 0, height: 0)
    }
}

Solution 15 - Ios

I managed to fix the same issue by calling

collectionView.delegate = self

BEFORE

collectionView.dataSource = self

I have static items and never reload the data. Apparently setting the dataSource triggers the loading of the collection data synchronously, so if the delegate is not set at this point, then sizeForItemAtIndexPath never gets called (unless reloadData is called later).

Solution 16 - Ios

If you're using autolayout, make sure collectionView.translatesAutoresizingMaskIntoConstraints = false is set.

Solution 17 - Ios

For me (in Swift 3.1) the method must be declared public like this:

    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
       return CGSize()
    }

Don't forget to make it public.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionjohn doeView Question on Stackoverflow
Solution 1 - IosalmasView Answer on Stackoverflow
Solution 2 - IosZenman CView Answer on Stackoverflow
Solution 3 - IosShiv KumarView Answer on Stackoverflow
Solution 4 - IosXysView Answer on Stackoverflow
Solution 5 - IosGaurav RamiView Answer on Stackoverflow
Solution 6 - IosH S ProgrView Answer on Stackoverflow
Solution 7 - IosManishView Answer on Stackoverflow
Solution 8 - IosAzamView Answer on Stackoverflow
Solution 9 - IosStephen RainsView Answer on Stackoverflow
Solution 10 - IosMuzammilView Answer on Stackoverflow
Solution 11 - Ios烛龙一现View Answer on Stackoverflow
Solution 12 - IosCharlie SeligmanView Answer on Stackoverflow
Solution 13 - IosAbdul Malik AmanView Answer on Stackoverflow
Solution 14 - IosAbhiView Answer on Stackoverflow
Solution 15 - IosSébastienView Answer on Stackoverflow
Solution 16 - IosBrian GreenView Answer on Stackoverflow
Solution 17 - IosOliver EichhornView Answer on Stackoverflow