UICollectionView cellForItemAt:在layoutAttributesForElements返回值时不会被调用

时间:2018-02-13 08:30:52

标签: ios swift uicollectionview uicollectionviewlayout

我的自定义UICollectionView有点复杂UICollectionViewLayout。 我在其上添加了一个捏手势行为,并根据该结果调整布局。 它基本上运作良好,在正常情况下,细胞大小调整并重新定位。

但是当遇到特定情况时,细胞会消失,再也不会出现。 到目前为止,我无法澄清这种情况,但是当你将视图压缩到较小的尺寸时,它经常发生。

问题是,我的集合视图布局中调用了layoutAttributesForElements(当然这也暗示了numberOfCells:inSection也被调用)并且它返回了合理的单元格几何,但实际的单元格生成({{ 1}})不会被调用。

在进入代码之前(因为它有点太长而且复杂)我想问你们,你们是否有过同样的情况。 以下是到目前为止发生的事情和我看到的内容的摘要。

  • 并非总是发生。只有在挤压并达到一定条件后才会发生。所以这不是一种基本的使用方式-UICollectionView问题。
  • 即使发生了 cellForItemAt:一直被召唤(因为你一直在捏)
  • 布局属性没有疯狂值,例如零大小或远离视图范围的位置。它们都具有适合集合视图内容大小的位置属性。
  • 集合视图声明了正确的内容视图大小(至少在调试器上报告。)
  • 当它发生时,您无法在View Debugger中的视图层次结构中看到任何单元格。意思是,它不是零大小或清晰的颜色,但单元格本身已经消失。这对应于未调用cellForItemAt:的事实。
  • 发生这种情况后,即使您将屏幕捏回原始比例,也无法看到细胞。

任何信息都表示赞赏。谢谢!

修改

我的收藏视图布局是这样的。这个项目是一个音乐音序器,集合视图以钢琴卷风格显示你的音符。

layoutAttributesForElements

1 个答案:

答案 0 :(得分:0)

听起来像一个有趣的问题......

有关您的自定义UICollectionViewLayout子类(即代码)的更多信息会很有用,但我可以概述UICollectionView通常如何更新可见内容以响应边界更改(即内容偏移,轮换) )和invalidateLayout来电。

invalidateLayout触发内部属性时,缓存被清除,表示需要在下一个layoutSubviews传递时询问布局应该可见的内容。相反,如果布局无效且属性在缓存中已知,则不会询问布局。

当前CA事务提交并且UICollectionView layoutSubviews被调用时,所有这一切都会发生。此时,根据当前"可见边界"计算屏幕上最后已知的内容与屏幕上现在应该显示的内容之间的差异。 (实际上是滚动视图的边界,其中包括布局中的偏移量)。

在新的可见边界中不再可见的单元格将返回到重用队列,并且将构建新出现的单元格(根据布局),并且将使用其新属性更新现有项目(已更改)。

根据您的描述,听起来好像下一个layoutSubviews触发查询的属性(可能来自缓存!)没有为新的可见边界返回任何内容因此没有" new&# 34;出现 - 随着现有项目消失......

要调查的一些事项可能包括:

  1. 您的手势会导致您的自定义布局无效吗?如果没有,那么UICollectionView可能应该知道不信任它的内部属性缓存,并且总是在" diffing"期间询问​​布局是否有新属性。过程

  2. 在捏合手势期间,集合的界限如何变化? 这会直接影响差异,因为它将使用此可见边界来确定接下来应显示的内容。

  3. 您的布局如何回应shouldInvalidateForBoundsChange:? 大多数布局仅在扩展区(例如旋转)发生变化时无效,因此UICollectionView通常在执行diff时依赖于它的缓存属性。在你的情况下,如果你在手势中调整边界,你将在这里无条件地返回YES。

  4. 当你进入这个不稳定的状态时,你可能会尝试暂停调试器,例如。

    po [[cv collectionViewLayout] invalidateLayout] 
    po [cv setNeedsLayout] 
    po [cv layoutIfNeeded]
    
  5. ...并继续。一切都重新出现了吗?

    如果是这样,听起来布局在某些情况下不会失效,并且返回的属性确实合理。

    如果没有,请通过以下方式ping布局,看看它是否合理报告是合理的:

    po [[cv collectionViewLayout] layoutAttributesForElementsInRect:cv.bounds]