I'm creating a basic collection view layout which subclasses UICollectionViewFlowLayout
. However, I'm noticing that there appear to be several decoration views stacked on top of one another.
Whenever the user selects an item in the last section, I'm adding a new section with the code below. It seems that whenever I execute this code, one additional copy of the decoration view is being added to each already existing section.
[collectionView performBatchUpdates:^{
currentModelArrayIndex++;
[collectionView insertSections:[NSIndexSet indexSetWithIndex:currentModelArrayIndex]];
[collectionView reloadSections:[NSIndexSet indexSetWithIndex:currentModelArrayIndex-1]];
} completion:^(BOOL finished) {
[collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:currentModelArrayIndex] atScrollPosition:UICollectionViewScrollPositionTop animated:YES];
}];
I've corroborated this by giving my decoration views an alpha
of 0.2f
and seeing them stack up.
I also performed a dump of the collection view hierarchy and saw 10 instances of AFDecorationView
when I should only see 4:
| <AFDecorationView: 0x719ee50; baseClass = UICollectionReusableView; frame = (0 65; 768 208.125); alpha = 0; hidden = YES; layer = <CALayer: 0x719eec0>>
| <AFDecorationView: 0x71ad980; baseClass = UICollectionReusableView; frame = (0 333.125; 768 203.281); alpha = 0; hidden = YES; layer = <CALayer: 0x71adb60>>
| <AFDecorationView: 0x71afc90; baseClass = UICollectionReusableView; frame = (0 65; 768 208.125); layer = <CALayer: 0x71afd60>>
| <AFDecorationView: 0xd79ac30; baseClass = UICollectionReusableView; frame = (0 596.406; 768 203.281); alpha = 0; hidden = YES; layer = <CALayer: 0xd79ad00>>
| <AFDecorationView: 0xd79cf20; baseClass = UICollectionReusableView; frame = (0 333.125; 768 203.281); layer = <CALayer: 0xd79cff0>>
| <AFDecorationView: 0xd79dac0; baseClass = UICollectionReusableView; frame = (0 65; 768 208.125); layer = <CALayer: 0xd79a980>>
| <AFDecorationView: 0xd794fd0; baseClass = UICollectionReusableView; frame = (0 859.688; 768 225.938); layer = <CALayer: 0xd7950a0>>
| <AFDecorationView: 0xd7a1300; baseClass = UICollectionReusableView; frame = (0 596.406; 768 203.281); layer = <CALayer: 0xd7a13d0>></CALayer:>
| <AFDecorationView: 0xd7a35d0; baseClass = UICollectionReusableView; frame = (0 65; 768 208.125); layer = <CALayer: 0xd794470>>
| <AFDecorationView: 0xd7a43e0; baseClass = UICollectionReusableView; frame = (0 333.125; 768 203.281); layer = <CALayer: 0xd7a44b0>>
I have tried looking at another custom layout example, but they seem to instantiate quite a few instances of their decoration views, too. Could this be a bug in UICollecionView
? Or is it up to us to only add the decoration view layout attribute in layoutAttributesForElementsInRect:
once per section?
The decoration-related parts of custom layout look like the following.
@implementation AFCollectionViewFlowLayout
-(id)init
{
if (!(self = [super init])) return nil;
[self registerClass:[AFDecorationView class] forDecorationViewOfKind:AFCollectionViewFlowLayoutBackgroundDecoration];
return self;
}
#pragma mark - Private Helper Methods
-(void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)attributes
{
//implemented
}
#pragma mark - Overridden Methods
#pragma mark Cell Layout
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *attributesArray = [super layoutAttributesForElementsInRect:rect];
NSMutableArray *newAttributesArray = [NSMutableArray array];
for (UICollectionViewLayoutAttributes *attributes in attributesArray)
{
[self applyLayoutAttributes:attributes];
if (attributes.indexPath.item == 0)
{
UICollectionViewLayoutAttributes *newAttributes = [self layoutAttributesForDecorationViewOfKind:AFCollectionViewFlowLayoutBackgroundDecoration atIndexPath:attributes.indexPath];
[newAttributesArray addObject:newAttributes];
}
}
attributesArray = [attributesArray arrayByAddingObjectsFromArray:newAttributesArray];
return attributesArray;
}
#pragma mark Decoration View Layout
-(UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:decorationViewKind withIndexPath:indexPath];
if ([decorationViewKind isEqualToString:AFCollectionViewFlowLayoutBackgroundDecoration])
{
UICollectionViewLayoutAttributes *tallestCellAttributes;
NSInteger numberOfCellsInSection = [self.collectionView numberOfItemsInSection:indexPath.section];
for (NSInteger i = 0; i < numberOfCellsInSection; i++)
{
NSIndexPath *cellIndexPath = [NSIndexPath indexPathForItem:i inSection:indexPath.section];
UICollectionViewLayoutAttributes *cellAttribtes = [self layoutAttributesForItemAtIndexPath:cellIndexPath];
if (CGRectGetHeight(cellAttribtes.frame) > CGRectGetHeight(tallestCellAttributes.frame))
{
tallestCellAttributes = cellAttribtes;
}
}
CGFloat decorationViewHeight = CGRectGetHeight(tallestCellAttributes.frame) + self.headerReferenceSize.height;
layoutAttributes.size = CGSizeMake([self collectionViewContentSize].width, decorationViewHeight);
layoutAttributes.center = CGPointMake([self collectionViewContentSize].width / 2.0f, tallestCellAttributes.center.y);
layoutAttributes.zIndex = -1;
}
return layoutAttributes;
}
@end
I only want one decoration view per section, so I'm adding the decoration view to the first section.
This appears to be a bug in UICollectionView
. I've filed a bug report with Apple.
I had a similar issue but I was able to solve it by manually removing all decoration views in prepareLayout
in my custom layout class (I do that right before I invoke [super prepareLayout]
):
// Iterate over all subviews to remove all decoration views
for (UIView *view in self.collectionView.subviews)
{
if ([view isKindOfClass:[DecorationView class]])
{
[view removeFromSuperview];
}
}
[super prepareLayout];
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