CollectionView sizeForItemAtIndexPath 从未被调用。

117

这让我疯狂!我有一个如下所示的UICollectionViewController

class PhrasesCompactCollectionViewController: UICollectionViewController

numberOfSectionscellForItemAt 被调用了,但是sizeForItemAtIndexPath从未被调用。我在别的地方使用完全相同的代码,它可以正确触发。我使用的是 Xcode 8 Beta 6。

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

280

您需要在类声明中指定实现协议UICollectionViewDelegateFlowLayout

class PhrasesCompactCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout


13
我做了这件事,但仍然没有被叫到。 :( - Van Du Tran
1
真烦人,我在尝试使用sizeForItemAt时没有设置流布局代理却没有收到错误提示。浪费了2个小时来调试 :/ - Onur Çevik

76

我也遇到了同样的问题。唯一帮助我的方法是将collectionView尺寸检查器下的'Cell Size'的“Estimated Size”设置为“None”。

输入图像描述


1
不知何故,所有其他关于使用sizeForItemAt的帖子上的所有其他答案都没有提到这一点。非常有用。 - JCutting8
这太疯狂了!!!我在iPhone 5模拟器上测试了10.3.1 iOS版本,并且该方法被调用。但是在iPhone 5s模拟器上,使用10.3.1版本时该方法却没有被调用!!!我将估算大小更改为“无”,然后在iPhone 5s上开始调用该方法。真是太神奇了! - hasan
非常感谢!我的自定义sizeForItemAt集合视图在Xcode 11.4之前一直运行良好,但突然间单元格的宽度出现了问题。尝试了很多方法,最终这个方法解决了问题。 - Filip
谢谢!苹果让这些小事变得极其复杂,这既令人沮丧又愤怒,我们都不得不在这里讨论它。 - KMW
你如何在没有故事板的情况下设置它? - henrique

65

Swift 3+ 中,请使用此方法:

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

如果您正在使用UICollectionView,请确保您的类同时符合以下两个委托:

  • UICollectionViewDelegate

  • UICollectionViewDelegateFlowLayout


5
因为UICollectionViewController已经实现了UICollectionViewDelegate,所以在遵循协议时这样做是多余的。 - Van Du Tran
4
声明"它是必需的"并不是多余的,因为成为UICollectionViewController并非必须要求... - Michael Hudson
我认为你的意思是非集合视图,Viewcontroller可以成为UICollectionViewDelegate。 - ScottyBlades
1
UICollectionViewDelegateFlowLayout继承自UICollectionViewDelegate,因此只需实现UICollectionViewDelegateFlowLayout即可。 - evya

35

Swift 5

所有这些步骤都是必需的

  1. 符合 UICollectionViewDelegateFlowLayout 接口<== 绝对需要!!
  2. 以及 UICollectionViewDelegate, UICollectionViewDataSource 接口
  3. 在 viewDidLoad 中设置以下内容:collectionView.delegate = selfcollectionView.dataSource = self
  4. 在界面构建器中将 Estimate Size 设置为 None
  5. 确保以下方法使用 sizeForItemAt 而不是 sizeForItemAtIndexPath

如下:

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

8
估计大小为"None" - 救了我的一天! - Joe Hallenbeck
1
如果您没有使用IB,如何在编程中将“估计大小设置为无”? - henrique

17

Swift 3

设置UICollectionView的Cell尺寸,需要创建并自定义UICollectionViewFlowLayout对象,然后自定义属性并将该布局对象设置为UICollectionView对象。

根据您的需求更改cellheight和cellWidth对象(即您想要的单元格高度和宽度)。

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

请注意:如果您添加了sizeForItemAt indexPath方法,则必须移除该方法...

删除以下方法

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

}

12
这有什么帮助吗? - almas
1
Almas,这对于设置UICollectionViewCell的自定义单元格大小很有帮助...有变量cellWidth和cellHeight,你可以定义自己的数值...同时,“layout.sectionInset”、“layout.minimumLineSpacing”和“layout.minimumInteritemSpacing”,这些变量也会影响UICollectionViewCell的大小。 - Gaurav Rami
2
只有当所有单元格的大小相同时,此方法才有效。下面的答案是正确的答案。 - JeffN
这是用于更改 UICollectionView 的大小,而不是视图中的单元格。 - Async-
这不是为什么委托方法没有被调用的答案。 - Ziv Kesten

13

首先,需要确认一下是否符合 UICollectionViewDelegateFlowLayout 协议。然后,在 viewDidLoad() 中编写以下代码:

//告诉 UICollectionView 使用你的 UIViewControllerUICollectionViewDelegateFlowLayout 方法

collectionView.delegate = self

// 如果你想设置自己的集合视图流布局

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

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

使用此代码UICollectionViewDelegateFlowLayout方法

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

这个方法会被调用,你可以在其中设置大小。


8

如果没有答案生效,您需要检查以下三个方面:

  1. 实现FlowLayout Delegate: class MyController: UICollectionViewController, UICollectionViewDelegateFlowLayout

  2. 使用此方法来设置item的大小(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. 在UICollectionView的Inspect元素中选择Estimate size = None


1
如果您没有使用IB,如何通过编程方式将“Estimate size to None”设置为无? - henrique

2
请确保将此代码放置在viewDidLoad()方法中。
最初的回答。
collectionView.delegate = self

2

我曾经遇到过同样的问题,但是无论我怎么尝试都无法解决。我看到了一个黄色的警告,提示我将其设置为私有属性,因为它与Layout Delegate定义的另一个函数很接近。最终我解决了这个问题,方法如下:

将原来的函数名更改一下,以便与Layout Delegate中的函数不重复即可。

希望对你有所帮助!

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

注意"sizeForItemAtIndexPath"和正确的"sizeForItemAt"之间的区别。
我为了解决这个问题纠结了好几天,最终成功了。以下是我所有的函数,展示了我如何通过将高度设置为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)
    }
}

0

你可能设置了错误的布局:UICollectionViewLayout,实际上应该是UICollectionViewFlowLayout这样的布局。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接