如何修复具有自定义尺寸单元格的uicollectionviewflowlayout的内容插图?

时间:2019-04-25 05:07:50

标签: swift collections uicollectionview uicollectionviewlayout

我正在实现水平的自定义UICollectionViewFlowLayout,第一个/最后一个单元格应该位于视图的中间,并且具有自定义大小的单元格。

问题是,正确的sectionInset大于我的预期-未知的间隙添加到正确的sectionInset。

我实现了以下方法。

    自定义单元类的
  1. preferredLayoutAttributesFitting(_ :)
    • 计算其中包含数据的项目的新单元格大小。
  2. estimatedItemSize
    • 我发现,当使用preferredLayout〜方法时,估计的ItemSize是必需的,否则会崩溃。
  3. shouldInvalidateLayout(forPreferredLayoutAttributes〜)
    • 在所有项目均无效时返回true。
  4. invalidationContext(forPreferredLayoutAttributes〜)
    • 在这种方法中,我在本地数组中附加了preferredAttributes,以便以后使用它们来计算sectionInset。
  5. prepare()
    • 首次调用后计算出的sectionInset。
    • 左插图:从collectionView宽度中减去第一项的宽度,并一分为二。
    • 右插图:从collectionView宽度中减去最后一项的宽度,并一分为二。

我想这个问题可能是由估计的项目大小引起的,但是如果没有它,它就会崩溃。

final class CustomCell: UICollectionViewCell {
    ...
    override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
        let optimalSize = systemLayoutSizeFitting(UIView.layoutFittingExpandedSize)
        var newFrame = layoutAttributes.frame
        newFrame.size.width = optimalSize.width + 10
        layoutAttributes.frame = newFrame
        return layoutAttributes
    }
    ...
}
class CustomCollectionViewLayout: UICollectionViewFlowLayout {
    override func prepare() {
        guard isInitialSetupDone else {
            scrollDirection = .horizontal
            estimatedItemSize = CGSize(width: 30, height: 40)
            minimumInteritemSpacing = 23.3

            isInitialSetupDone = true
            return
        }

        // Set sectionInset after invalidation of all items
        guard
            cache.count == numberOfItems,
            let firstItem = cache.first,
            let lastItem = cache.last else { return }

        let contentSize = collectionViewContentSize
        let leftInset   : CGFloat = (width - firstItem.frame.width) / 2
        let rightInset  : CGFloat = (width - lastItem.frame.width) / 2
        sectionInset = UIEdgeInsets(top: 3.6, left: leftInset, bottom: 3.6, right: rightInset)

        cache.removeAll(keepingCapacity: true)
    }

    override func shouldInvalidateLayout(forPreferredLayoutAttributes preferredAttributes: UICollectionViewLayoutAttributes,
                                         withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> Bool {
        let hasOnlyOneItem = (numberOfItems == 1)
        let allItemsInvalidated = (cache.count == numberOfItems)

        if hasOnlyOneItem {
            return true
        } else if allItemsInvalidated {
            return false
        } else {
            return true
        }
    }

    override func invalidationContext(forPreferredLayoutAttributes preferredAttributes: UICollectionViewLayoutAttributes,
                                      withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutInvalidationContext {
        let context = super.invalidationContext(forPreferredLayoutAttributes: preferredAttributes, withOriginalAttributes: originalAttributes)
        cache.append(preferredAttributes)
        return context
    }
}

0 个答案:

没有答案