在发生自调整大小之前,如何准确地为 UICollectionViewLayout 提供矩形中的元素?

Posted

技术标签:

【中文标题】在发生自调整大小之前,如何准确地为 UICollectionViewLayout 提供矩形中的元素?【英文标题】:How do I accurately provide elements in a rect for UICollectionViewLayout before self-sizing has occurred? 【发布时间】:2018-07-17 20:23:53 【问题描述】:

我正在使用UICollectionView 构建可以在网格或垂直列表布局中显示元素的 UI。 UICollectionViewFlowLayout 不适合全宽列表布局,所以我正在编写自己的 UICollectionViewLayout 子类。并且行是自定大小的,因此它们可以具有多行标签并将其字体大小与系统字体大小设置相匹配,并根据需要增大/缩小

在内部,它具有所有行的布局属性集合。在prepareLayout(Swift 中为prepare)中,我遍历数据源中的所有索引路径,并创建布局属性,并将它们的框架设置为估计的行高。

shouldInvalidateLayoutForPreferredLayoutAttributes 中,如果高度与集合中该行的值不同,我将返回YES。然后在invalidationContextForPreferredLayoutAttributes 中,我使传入的preferredAttributes 的索引路径之后的所有项目都无效,因为这一行的高度变化会影响所有后续行的垂直位置。然后再次调用prepareLayout,并根据需要更新所有内容的框架。

问题出现在这一系列事件中:

layoutAttributesForElementsInRect 被调用。我检查了所有属性并检查CGRectIntersectsRect(attr.frame, rect)shouldInvalidateLayoutForPreferredLayoutAttributes 为即将出现的每一行调用。其中一些最终比最初的估计高度要小。

如果总行收缩足够大,则不在layoutAttributesForElementsInRect 的矩形内的一两行将向上移动到应该出现的程度。例如,如果矩形的 y 值介于 0 到 1334 之间,那么在调用 shouldInvalidateLayoutForPreferredLayoutAttributes 之前,y 原点为 1340 的行现在可能位于 1300。但是布局对象已经“知道”哪些行应该在屏幕上,所以那些行只是不显示,我的列表中有漏洞。

我可以通过从layoutAttributesForElementsInRect 返回额外的行来解决这个问题(通过将我得到的矩形垂直扩展 100 点或其他东西)。但这是一个 hack,这似乎是 API 应该有办法解决的问题。但是在自我调整大小完成后,我没有再接到layoutAttributesForElementsInRect 的电话,而且我看不到要求通过UICollectionViewLayoutInvalidationContext 再次调用它的方法。

那么...我是否遗漏了 API 中的一些明显内容?这是一个不应该发生的问题,这意味着我正在处理错误的事情吗?在self-sizing发生之前似乎没有办法准确回答layoutAttributesForElementsInRect...?

说明问题的示例代码是 GitHub 上的 here。

【问题讨论】:

【参考方案1】:

我发现,当您拥有自定大小的补充视图时,invalidationContextForPreferredLayoutAttributes 中的额外失效会导致出现布局间隙的错误。我犯了同样的错误,其他人也犯了同样的错误,因为使下面的项目无效并且项目自定大小似乎是合乎逻辑的。我的猜测是集合视图会为您处理这个问题。

这些are the lines 要在您的示例项目中删除:

[result invalidateItemsAtIndexPaths:rowPaths];
[result invalidateSupplementaryElementsOfKind:UICollectionElementKindSectionHeader atIndexPaths:headerPaths];

我已就此向 Apple 提交了文档更新 Radar。 http://www.openradar.me/35833995

【讨论】:

在我有一个固定项目大小但可自行调整可重用视图的情况下,我在 ios 11 和 12 上遇到了崩溃问题,这是由通过 super 调用的 collectionview invalidationLayout(context) 的内部工作引起的。为了解决它,下面的 ios 12 我不调用 super 并手动组装上下文。【参考方案2】:

我的问题是我从自定义布局返回的布局属性缺少 zIndex 属性,因此自调整大小无法正常工作。

【讨论】:

以上是关于在发生自调整大小之前,如何准确地为 UICollectionViewLayout 提供矩形中的元素?的主要内容,如果未能解决你的问题,请参考以下文章

如何在绘制之前获取调整大小的自定义视图的宽度和高度

UICollectionView - 在设备旋转上调整单元格大小 - Swift

如何调整自定义 UITableViewCell nib 文件的大小以适合 tableView?

如何在 Xamarin.UWP 中调整大小和减小大小(使用压缩质量值)

自调整大小表格单元格中的 ImageView 在应用 Aspect Fit 之前使用图像的高度

Elementor - 滚动“运动效果”在调整窗口大小之前不起作用