【发布时间】:2019-03-09 14:23:11
【问题描述】:
我的目标是在UICollectionView 中拥有动态大小的单元格。此外,当UICollectionView 的可滚动contentWidth 小于集合的bounds 时,我希望项目在集合中居中。
目前的方法:
我正在尝试以最简洁的方式做到这一点。我有自我调整大小UICollectionViewCells,其中自动布局可以根据内容的约束来确定单元格的大小。为此,我的单元格会覆盖 preferredLayoutAttributesFitting 函数,并为其内容返回适当的宽度。
我的自定义UICollectionViewFlowLayout 子类使用UICollectionViewCell 提供的宽度信息来正确调整单元格的大小。
在我的自定义 UICollectionViewFlowLayout 上覆盖的唯一方法是:
layoutAttributesForItem(at...)layoutAttributesForElementsIn(rect...)shouldInvalidateLayout(forBoundsChange...)
UICollectionViewCells 的动态调整大小完美无缺。
问题:
使用这种方法,我不知道每个单元格的大小(每个单元格都可以不同)。我想实现UICollectionView 的delegate 方法来提供一个插入以使我的内容在集合视图中居中。为此,我认为我应该实施并覆盖
collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
问题在于 inset 方法在布局过程的早期被调用,我不知道将在布局期间确定的contentSize。
这里是各种布局方法的堆栈,对于一个完整的布局传递,按照它们运行的顺序:
prepare started
prepare finished
layoutAttributesForElementsInRect started
layoutAttributesForElementsInRect finished
layoutAttributesForElementsInRect started
layoutAttributesForElementsInRect finished
layoutAttributesForElementsInRect started
layoutAttributesForElementsInRect finished
prepare started
insetForSectionAt 0 called <--- The datasource has knowledge of the presence of cells but the cells themselves are not yet dequeued
prepare finished
layoutAttributesForElementsInRect started
layoutAttributesForItemAt [0, 0] started
layoutAttributesForItemAt [0, 0] finished
layoutAttributesForItemAt [0, 1] started
layoutAttributesForItemAt [0, 1] finished
layoutAttributesForItemAt [0, 2] started
layoutAttributesForItemAt [0, 2] finished
layoutAttributesForElementsInRect finished
layoutAttributesForElementsInRect started
layoutAttributesForItemAt [0, 0] started
layoutAttributesForItemAt [0, 0] finished
layoutAttributesForItemAt [0, 1] started
layoutAttributesForItemAt [0, 1] finished
layoutAttributesForItemAt [0, 2] started
layoutAttributesForItemAt [0, 2] finished
layoutAttributesForElementsInRect finished
prepare started
prepare finished
layoutAttributesForElementsInRect started
<--- At this point Cells DO return valid sizes through Autolayout
layoutAttributesForItemAt [0, 0] started
layoutAttributesForItemAt [0, 0] finished
layoutAttributesForItemAt [0, 1] started
layoutAttributesForItemAt [0, 1] finished
layoutAttributesForItemAt [0, 2] started
layoutAttributesForItemAt [0, 2] finished
layoutAttributesForElementsInRect finished
对于单个布局传递,对各种布局方法进行多次调用,但仅在最后,来自不同单元格的 Auto-layout 的大小信息可用于传递到布局。
我注意到sectionInset 委托函数在单元被正确出列并允许运行其自动布局约束之前被提前调用。因此,在 inset 被调用的时候不可能通知它正确的值。
使用这种方法,是否可以在布局通过后强制调用重新计算sectionInsetAt,还是我应该完全改变技术?
我尝试过的事情:
我尝试从insetForSectionAt 委托函数中查询collectionViewLayout 的collectionViewContentSize。不幸的是,这不能在布局过程中使用,因为布局当前正在进行中。它会导致崩溃并出现错误:
[CollectionView] An attempt to update layout information was detected while already in the process of computing the layout (i.e. reentrant call). This will result in unexpected behaviour or a crash. This may happen if a layout pass is triggered while calling out to a delegate. UICollectionViewFlowLayout instance is (<App.ViewportToolbarFlowLayout: 0x7f8a5261add0>)
我尝试使用collectionView 的contentSize 方法在insetForSectionAt 委托方法执行期间获取大小,但它在布局过程中运行时没有提供正确的数据。
【问题讨论】:
标签: ios swift uicollectionview