【问题标题】:Intrinsic content sized UICollectionView inside UITableViewUITableView 内的内部内容大小的 UICollectionView
【发布时间】:2019-07-18 09:46:16
【问题描述】:

让我先说在过去几个月里我花了大约 100 个小时搜索 Google 和 StackOverflow 试图回答这个问题。我已经遵循了许多教程,但无法解决我的问题。每个人都非常失望,令人沮丧。

期待

现实

问题

我有一个包含 UIView 的 UITableView。 UIView 具有自动布局约束,将其固定在单元格边缘 15pt 处,然后我给它一个阴影和圆角。在那个 UIView 里面,我有几个标签,然后是一个 UICollectionView 和一个堆栈视图。

我的 UICollectionView 的高度一直为 0,我不知道如何使它具有内在大小。我似乎可以让它正确显示的唯一方法是通过情节提要内的自动布局强制它具有特定的高度(这是我为截取此屏幕截图所做的)。不幸的是,强制这样的高度是不现实的,原因有两个:

  1. 高度因设备宽度而异。由于图像是正方形,因此高度大致(但不完全)是设备宽度的一半。
  2. 如果没有图像,则集合视图的高度应为 0。

似乎真的应该可以在这里使用流布局的内在内容大小。

故事板

约束

我在每个标签、集合视图和堆栈视图之间留出了大约 15pt 的空间(因此,垂直空间)。集合视图原型单元格中有一个图像视图。图像视图的顶部、底部、尾部和前导空间都设置为集合视图单元格的 0,并且比例也是 1:1。

集合视图布局

为了实现一张大图和四张小图的布局,我用的是SNCollectionViewLayout

数据源/委托

在我的控制器中,在 viewDidLoad 中,我已将 UITableView 的 estimatedRowHeight 设置为 400,并将 rowHeight 设置为 UITableView.automaticDimension

在tableView cellForRowAt 中,我将一个可重用的自定义UITableViewCell 类出列,在表格视图单元格上设置各种出口,并在表格视图单元格的集合视图上调用reloadData()。在故事板中,我将表格视图单元格设置为集合视图的数据源和委托。

在表格视图单元格的awakeFromNib 函数中,我设置了圆角半径、阴影,并使用以下代码在集合视图上进行流布局(您可以在他们的示例中看到):

let snCollectionViewLayout = SNCollectionViewLayout()
snCollectionViewLayout.fixedDivisionCount = 4
snCollectionViewLayout.delegate = self
snCollectionViewLayout.itemSpacing = 10
collectionView.collectionViewLayout = snCollectionViewLayout

我还通过编写以下函数实现了可选的SNCollectionViewLayoutDelegate 协议:

func scaleForItem(inCollectionView collectionView: UICollectionView, withLayout layout: UICollectionViewLayout, atIndexPath indexPath: IndexPath) -> UInt {
    if indexPath.row == 0 || collectionView.numberOfItems(inSection: indexPath.section) <= 2 {
        return 2
    } else {
        return 1
    }
}

这个函数就是为什么第一张图片的高度和宽度是其他图片的两倍。

研究

为了弄清楚这一点,我检查了表格视图单元格的 cellForRowAt 和 willDisplay 方法中的collectionView.collectionViewLayout.collectionViewContentSize。无论哪种情况,它都是 (0,0)。

我还尝试在集合视图单元格的 cellForItemAt 和 willDisplay 中检查它。除非我在集合视图中添加高度约束以强制它变高,否则这些日志行甚至不会打印,但是我没有一个好的方法可以将高度降低到应有的水平,并且任何时候我'试过了,我得到了冲突的约束警告和非常不稳定的拉伸视图(例如堆栈视图被完全压扁)。

在测试中,我强制设置了一个足够大的高度约束以适应集合视图,当发生这种情况时,它会正确呈现并且集合视图内容大小是正确的,所以我知道它能够跟踪(可以看到here)。

有人对此有任何见解吗?如果您有任何要研究的细节,我很乐意提供更多代码。我试图给出完整的画面,同时尽可能简短(我知道它很长)。

我觉得这个问题与集合视图位于表格视图单元格内有关。

提前致谢。

【问题讨论】:

  • 你实现了 UICollectionViewDelegateFlowLayout 吗?给 sizeForItemAt indexPath.
  • @HardikThakkar 我没有,但我试图让它自动调整大小,而不是自己手动计算大小。 SNCollectionViewLayout 应该计算每个单元格的宽度,基于我将其设置为 4 列、单元格之间 10pt 以及我给每个单元格的比率(第一个是大小的 2 倍)这一事实。默认情况下,它通过将单元格的高度设置为等于它计算的宽度,使每个单元格成为正方形。 github.com/ahmedAlmasri/SNCollectionViewLayout/blob/master/…
  • 也知道我的第一个屏幕截图实际上是 iOS 模拟器的屏幕截图,但要做到这一点,我必须通过情节提要强制集合视图到一个高度,并且我试图避免弄清楚如何手动计算。集合视图能够调整内容的内在大小,所以我应该能够自动调整大小。

标签: ios swift uitableview uicollectionview intrinsic-content-size


【解决方案1】:

在表格视图单元格中保持高度约束连接。

@IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!

并根据高度计算以编程方式更新高度约束值

self. collectionViewHeightConstraint.constant = 100 // set it to 0 if nothing to display 

【讨论】:

  • 我以前尝试过这种事情。我到底在哪里设置高度约束?我很难弄清楚这一点,因为我需要它来渲染集合视图,以便流布局计算出正确的高度。通常当我尝试这样做时,我会遇到自动布局错误,说它必须打破约束。如果你告诉我把它放在哪里,我会很乐意再试一次。
  • 每当你更新 tableview 单元格时,它必须是。您必须在 tableview 的数据源方法 cellForRow 中执行此操作(此时您也应该重新加载集合视图)
  • 我肯定会在cellForRowAt 中重新加载集合视图,所以那里没有问题,但是流布局还没有渲染,所以我不知道要设置它的高度。如果集合视图布局尚未完成工作,我如何确定将高度设置为什么?有没有办法强制它计算它的高度?或者可能是在集合视图呈现后设置高度约束的地方?
  • @Nate 有多少种不同的布局可能性来确定高度
  • @agibson007 好吧,每个设备 2 个:0 像素,几乎是屏幕宽度的一半。虽然,集合视图流布局能够解决这个问题,所以我有理由认为我错过了一些东西,让它只根据内容大小调整自己的大小。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-22
  • 1970-01-01
  • 2018-04-29
  • 2017-03-13
  • 1970-01-01
  • 2021-03-29
  • 1970-01-01
相关资源
最近更新 更多