首次加载时 UICollectionViewCell 内容大小错误

UICollectionViewCell content wrong size on first load

我已将 UICollectionView 添加到我的 UIViewController 并为其制作了一个自定义单元格。

我使用 sizeForItemAtIndexPath 方法设置单元格的大小,并将每个单元格的高度和宽度设置为 UIScreen.mainScreen().bounds.width/2。所以本质上,每个单元格都是屏幕宽度的一半,高度也是相同的长度。

然后我在单元格内有一个 UIImageView,每个边缘都固定到单元格的相对边缘,以便图像视图填充单元格。我还有一个 UILabel 在单元格中垂直和水平居中。

然而,在第一次加载时,单元格大小正确,但左上角的小方块中的内容要小得多。 (如下图所示,我已将单元格的 contentView 背景颜色设置为绿色,将 imageView 背景颜色设置为红色)。

然后在向下滚动一点后(我假设一个可重复使用的单元格被出列)所有单元格都很好(并且在向上滚动后保持良好)。

是什么导致内容在首次加载时未被正确约束?

更新

我的一些代码 UIViewController:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        var cell = collectionView.dequeueReusableCellWithReuseIdentifier("PrevDrawCell", forIndexPath: indexPath) as? PrevDrawCell

        if cell == nil {
            cell = PrevDrawCell()
        }

        cell!.drawVC = self
        cell!.imageShortCode = self.tempImageURLs[indexPath.row]

        // Pull image (async) and set after download
        cell!.setupImage()

        cell!.contentView.backgroundColor = UIColor.greenColor()
        cell!.coverView.backgroundColor = UIColor.redColor()

        cell!.dateLabel.font = UIFont(name: "HelveticaNeue-Light", size: 26)
        cell!.dateLabel.text = "\(self.tempImageURLs.count-indexPath.row)/9"

        return cell!
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    let size = UIScreen.mainScreen().bounds.width/2
        return CGSize(width: size, height: size)
}


func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
        return UIEdgeInsetsZero
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
    return 0
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
    return 0
}

看起来它仍然保留 contentView 的 100x100px 基本尺寸,而单元格本身已经获得正确的尺寸。您可以强制布局重置,在 return 单元格之前添加以下行:

cell?.layoutIfNeeded()

我曾经遇到过类似的问题(即使自动布局正确,我的单元格内容也不适合单元格)。该错误是由于未调用引起的 super.layoutSubviews() 在单元格 class.

中的重写函数 layoutSubviews() 中

对于使用 Storyboard + AutoLayout 并选择在运行时激活哪些约束的用户:

当使用 dequeueReusableCell 时,在第一次加载时,单元格已创建但其视图尚未初始化,因此不会保存约束更改 - 无论您在 Storyboard 中设置什么都会被使用。我的解决方案是在加载视图后更新约束:

override func layoutSubviews() {
    super.layoutSubviews()
    adjustIconWidths()
}

感谢 vin047 的精彩提示。

在我们的案例中,我发现问题出在超级调用顺序问题上。

但是使用总体table视图(或集合视图)。不在单元格中。

作品:

class UnusualCollectionView: UICollectionView {
    override func layoutSubviews() {
        super.layoutSubviews()
        contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
    }

非常不规律地失败,尤其是第一次出现时:

class UnusualCollectionView: UICollectionView {
    override func layoutSubviews() {
        contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
        super.layoutSubviews()
    }

这个问题导致了一些非常不稳定的行为。例如,第 12 个单元格(不是真的)总是垂直移动很长一段距离。始终是第 12 个单元格!谁知道?

vin047 在这里化险为夷,太棒了。

对我有用的是将 Collection 视图上的 Estimate Size 从自动更改为 None。

在我的例子中,我需要指定单元格的高度等于 collectionView 的高度。但是集合视图的高度取决于屏幕的大小。 所以里面 sizeForItemAt delegate

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

为了完成这项工作,我需要从 viewDidLayoutSubviews 调用 reloadData 函数

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    mycollection.reloadData()
}

我有一个类似的问题,不完全相同,但可以帮助别人。 我没有在单元格中调用 super.prepareForReuse() 就覆盖了 prepareForReuse。因此,当我将 UICollectionViewCompositionalLayout 与 .estimated(100) 一起用于单元格高度时,我在设备旋转时出现了奇怪的行为:如果旋转而不滚动,则在视图出现之后,然后滚动 - 你将拥有估计高度 (100) 的单元格,而不是随着布局更新。 所以,尝试检查这部分:

 override func prepareForReuse() {
     super.prepareForReuse()
 }

嘿伙计们,如果仍然有人因为自动调整单元格而无法设置内容大小,你可以将它添加到你的集合视图中,你可以获得内容大小

*此处滚动使视图获得正确的内容大小,因此使您的 CollectionView 可滚动或禁用它,在这两种情况下,您将在单元格中加载数据后获得内容大小

`XCollectionView.isScrollEnabled = true/false`

*然后从数据源重新加载数据

`XCollectionView.reloadData()`

*然后调用layoutneeded

`XCollectionView.layoutIfNedded()`

*然后你可以检查,内容大小将等于你的内容

`XCollectionView.collectionViewLayout.collectionViewContentSize.height`

*现在将集合视图的高度设置为内容高度,一切顺利