CollectionViewsizeForItemAtIndexPath 从未调用

这快把我逼疯了! 我有一个 UICollectionViewController,如下所示:

class PhrasesCompactCollectionViewController: UICollectionViewController

正在调用 numberOfSections 和 cellForItemAt,但从未调用 sizeForItemAtIndexPath。我正在其他地方使用相同的代码,它正确地触发。我用的是 Xcode 8 Beta 6。

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


return CGSize(width: 120, height:120)
}
66555 次浏览

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

class PhrasesCompactCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout

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 {


}

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

If You are using UICollectionView then make sure that your class complies both Delegate

  • UICollectionViewDelegate

  • UICollectionViewDelegateFlowLayout

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.

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.

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 :-(

Make sure you put this in viewDidLoad()

collectionView.delegate = self

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

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

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.

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

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 {


}

Just add: UICollectionViewDelegateFlowLayout

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

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

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

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

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