Environment:UICollectionView
that looks like UITableView
Custom UICollectionViewFlowLayout subclass to define the frame
of the DecorationView
Self-Sizing cells enabled
Expected behavior:
A DecorationView
that should be placed as a background for every section of the UICollectionView
Observed Behavior:
The DecorationView
collapses to an arbitrary size:
Seems that UICollectionView
tries to calculate an automatic size for the DecorationView
. If I disable Self-Sizing cells, the decoration view is being placed exactly at the expected place.
Is there any way to disable Self-Sizing for DecorationView
?
In my UICollectionViewFlowLayout
subclass I simply take the first and last cells in the section and stretch the background to fill the space underneath them. The problem is that UICollectionView
does not respect the size calculated there:
override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let collectionView = collectionView else {
return nil
}
let section = indexPath.section
let attrs = UICollectionViewLayoutAttributes(forDecorationViewOfKind: backgroundViewClass.reuseIdentifier(),
with: indexPath)
let numberOfItems = collectionView.numberOfItems(inSection: section)
let lastIndex = numberOfItems - 1
guard let firstItemAttributes = layoutAttributesForItem(at: IndexPath(indexes: [section, 0])),
let lastItemAttributes = layoutAttributesForItem(at: IndexPath(indexes: [section, lastIndex])) else {
return nil
}
let startFrame = firstItemAttributes.frame
let endFrame = lastItemAttributes.frame
let origin = startFrame.origin
let size = CGSize(width: startFrame.width,
height: -startFrame.minY + endFrame.maxY)
let frame = CGRect(origin: origin, size: size)
attrs.frame = frame
attrs.zIndex = -1
return attrs
}
It's possible that the frames of your decoration views are not being updated (i.e. invalidated) after the frames of your cells have been self-sized. The result is that the width of each decoration view remains at its default size.
Try implementing this function, which should invalidate the layout of the decoration view for each section every time the layout of an item in that section is invalidated:
override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext) {
let invalidatedSections = context.invalidatedItemIndexPaths?.map { $0.section } ?? []
let decorationIndexPaths = invalidatedSections.map { IndexPath(item: 0, section: $0) }
context.invalidateDecorationElements(ofKind: backgroundViewClass.reuseIdentifier(), at: decorationIndexPaths)
super.invalidateLayout(with: context)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With