CollectionView sizeForItemAtIndexPath never called
IosIos 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'.
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 :
- Conform to UICollectionViewDelegateFlowLayout <== Absolutely needed !!
- and to
UICollectionViewDelegate, UICollectionViewDataSource
- Set these in viewDidLoad :
collectionView.delegate = self
andcollectionView.dataSource = self
- Set Estimate Size to None in the Interface Builder
- 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:
-
Implement FlowLayout Delegate :
class MyController: UICollectionViewController, UICollectionViewDelegateFlowLayout
-
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) }
-
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.