UICollectionView sizeForItemAt 调用但大小不正确

Posted

技术标签:

【中文标题】UICollectionView sizeForItemAt 调用但大小不正确【英文标题】:UICollectionView sizeForItemAt Called But Not Sized Correctly 【发布时间】:2019-10-08 17:02:02 【问题描述】:

我希望第一个部分的单元格是集合视图的全宽,第二个部分是宽度的一半。启动时,单元格不尊重给定的宽度,尽管似乎尊重了高度。几秒钟后,collection view 被重新加载,并且大部分时间它将单元格设置为正确的大小。当手机的方向变为横向时,单元格会再次以不正确的大小绘制。

我尝试使用 UICollectionViewDelegateFlowLayout 和 sizeForItemAt 委托函数来设置单元格大小,但即使调用了该函数,它们也不遵循给定的大小。

目前,我正在设置部分插图,然后计算集合视图边界中单元格的剩余可用宽度,然后将宽度除以每行的单元格数。

class HomeCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout 

    let sectionInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

    override func viewDidLoad() 
        super.viewDidLoad()

        self.collectionView?.contentInsetAdjustmentBehavior = .always
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize 
        return CGSize(width: collectionView.frame.width, height: 44)
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets 
        return self.sectionInsets
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 
        return self.sectionInsets.left
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat 
        return 0
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
        var numberOfItemsPerRow: CGFloat = 1
        var height: CGFloat = 0

        switch indexPath.section 
        case 0:
            numberOfItemsPerRow = 1
            height = 97
        case 1:
            numberOfItemsPerRow = 2
            height = 126
        default:
            break
        

        let padding = self.sectionInsets.left * (numberOfItemsPerRow + 1)
        let availableWidth = collectionView.bounds.size.width - padding
        let width = availableWidth / numberOfItemsPerRow

        return CGSize(width: width, height: height)
    

这会导致单元格大小不正确,如下图所示。 Incorrect Example Image

只有在重新加载集合视图之后才能正确调整它们的大小。 Correct Example Image

此外,当手机转为横向时,它的显示不正确。 Incorrect Landscape Example Image

要结束我的问题,第一部分的单元格应始终占可用宽度的 100%。如果可能的话,如果他们有一个自动高度,那将是非常好的。我试过使用 UICollectionViewFlowLayout.automaticSize.height 但我认为这行不通。对于第二部分,它需要始终占据可用宽度的 50%。

【问题讨论】:

【参考方案1】:

如果您使用 Storyboard 创建 CollectionView。

我以为我必须invalidateLayout()。事实证明,ios 13 存在一个奇怪的错误。

您必须创建自己的 UICollectionViewFlowLayout。在您的viewDidLoad() 中调用类似的内容


        collectionView.collectionViewLayout = 
            let flowLayout = UICollectionViewFlowLayout()
            flowLayout.scrollDirection = .horizontal
            return flowLayout
        ()

【讨论】:

你的意思是 iOS 13,对吧? ;) 但是,是的,我的控制台 UICollectionViewFlowLayoutBreakForInvalidSizes 警告这样做了。 没什么大不了的,很清楚是什么意思。刚刚为其他阅读线程提供了反馈。干杯。【参考方案2】:

您必须使 viewDidLayoutSubviews 上的布局无效才能重新计算单元格的大小。 我附上了代码sn-p。试试这个

override func viewDidLayoutSubviews() 
    super.viewDidLayoutSubviews() 
    collectionView.collectionViewLayout.invalidateLayout()

【讨论】:

在 iOS 13.1 上将其添加到我的 UICollectionViewController 时导致无限循环。 它为我完成了工作。必须将其粘贴到扩展类中

以上是关于UICollectionView sizeForItemAt 调用但大小不正确的主要内容,如果未能解决你的问题,请参考以下文章

如何滚动另一个 UICollectionView 下方的 UICollectionView?

UICollectionView 单元内部已加载,但 UICollectionView 未显示

UICollectionView 断言失败 -[UICollectionView _updateWithItems:tentativelyForReordering:]

UITableviewCell 中的 UICollectionView。添加约束后,UICollectionView 不显示

将标题添加到 UICollectionView,而不是 UICollectionView 的部分

嵌套垂直 UICollectionView 和动态高度