【问题标题】:UICollectionViewCell content wrong size on first load首次加载时 UICollectionViewCell 内容大小错误
【发布时间】:2015-12-12 03:01:45
【问题描述】:

我在UIViewController 中添加了一个UICollectionView,并为其创建了一个自定义单元格。

我使用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
}

【问题讨论】:

  • 显示UIViewController
  • 你的意思是显示UIViewController的代码?
  • 我为UICollectionView 添加了一些代码。不确定您到底想看什么?
  • 几乎看起来像默认的 100x100px 单元格大小。如果你在 Xcode 中使用视图调试器,是单元格本身还是 contentView 仍然使用默认大小?如果在单元格上设置完所有内容后调用 layoutIfNeeded 会发生什么?
  • @DepartamentoB 在视图层次调试器中,当我选择实际单元格本身时,它是绿色背景的大小,而不是红色小方块。此外,刚刚尝试在 return cellcellForRowAtIndexPath 方法中调用 cell.layoutIfNeeded() 之前,这解决了它!在这里做这件事是件好事吗?它到底在做什么,有什么缺点吗?应该在我放的cellForRowAtIndexPath 中调用它还是在其他地方调用它?

标签: ios objective-c swift uicollectionview uicollectionviewcell


【解决方案1】:

看起来它仍然保留了 contentView 的 100x100px 基本大小,而单元格本身已经获得了正确的大小。您可以在返回单元格之前强制重置布局:

cell?.layoutIfNeeded()

【讨论】:

  • 很棒的回复,你拯救了我的一天!
  • 最后我使用了这个功能,它按预期工作。谢谢!
  • 使用 layoutIfNeeded() 解决第一次加载单元格或视图时可能遇到的任何尺寸相关问题,除非您调用 layoutIfNeeded() 它将等待下一个绘制周期应用与大小相关的更改,但是调用 layoutIfNeeded() 会立即应用这些更改!代码少,效果大!!
  • 出于某种原因,这是我从未开始工作的事情。我正在使用具有动态单元高度的完全自动布局,可能与此解决方案不兼容?即使做 layoutIfNeeded,当我检查单元格的帧大小时,它总是以 IB 中设置的大小响应。通常只有在回滚后才会响应正确的自动布局大小。
  • 对我来说,问题是容器视图的第一个尺寸错误,而单元格的框架是正确的!现在使用 layoutIfNeeded 效果很好!谢谢! :)
【解决方案2】:

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

【讨论】:

  • 我从来没有让that answer 工作,也没有覆盖 layoutSubviews。
  • 这解决了我的问题。在我的情况下,更具体地说,它位于 UICollectionViewCell 中。
  • 再重复一遍,称它“以错误的顺序”可能是关键。请注意,这似乎也适用于表格/集合视图本身 - 和/或单元格本身。
【解决方案3】:

对于那些使用 Storyboard + AutoLayout,并选择哪些约束在运行时处于活动状态:

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

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

【讨论】:

    【解决方案4】:

    感谢 vin047 的精彩提示。

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

    与整体表视图(或集合视图)。不在单元格中。

    作品:

    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 在这里拯救了这一天,太棒了。

    【讨论】:

      【解决方案5】:

      对我有用的是将 Collection View 上的 Estimate Size 从 Automatic 更改为 None。

      【讨论】:

      • 我为这个解决方案搜索了一个小时!
      • 这解决了我的单元格大小的问题,但内容视图仍以默认大小布局。
      • 这是正确答案,这样做并更改最小间距值
      • 这对我很有用!!!两个小时以来,我一直在寻找解决方案。
      • @bugloaf 面临与您的评论相同的问题,您找到解决方案了吗?
      【解决方案6】:

      在我的情况下,我需要将单元格的高度指定为等于 collectionView 的高度。但是集合视图的高度取决于屏幕的大小。 所以里面 sizeForItemAt 委托

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

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          【解决方案8】:

          如果仍然有人因为自动调整单元格大小而无法设置内容大小,您可以将其添加到您的收藏视图中,您可以获得内容大小

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

          `XCollectionView.isScrollEnabled = true/false`
          

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

          `XCollectionView.reloadData()`
          

          *然后调用layoutneeded

          `XCollectionView.layoutIfNedded()`
          

          *那么你可以检查一下,内容大小将等于你的内容

          `XCollectionView.collectionViewLayout.collectionViewContentSize.height`
          

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

          【讨论】:

            猜你喜欢
            • 2020-03-22
            • 1970-01-01
            • 2018-05-18
            • 1970-01-01
            • 2021-03-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多