I am trying to customise the positions of the headers in a UICollectionView
using a subclassed UICollectionViewFlowLayout
class (based loosely on the code for stacked headers which is shown enter link description here).
As a minimal test, let's say I just want to add a fixed offset to the position of all headers:
layoutAttributesForElementsInRect
so that all are always processed (this may be the cause of the problem, I'm not sure)layoutAttributesForSupplementaryViewOfKind
The full implementation is included at the end of this post.
(By the way, I know that adding all headers, including those outside the rect, is not strictly speaking necessary in the first step, but this is a simplified example of a more complex customisation in position I want to make which would cause all headers to be displayed in the draw rect.)
However, when I run the code I get the following NSInternalInconsistencyException
:
2014-01-15 00:41:50.130 CollectionStackedHeaders[60777:70b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: 'layout attributes for supplementary item at index path (<NSIndexPath: 0x8a7db90> {length = 2, path = 0 - 0})
changed from <UICollectionViewLayoutAttributes: 0x8a7f8b0> index path: (<NSIndexPath: 0x8a7d9c0> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionHeader); frame = (0 0; 320 50);
to <UICollectionViewLayoutAttributes: 0x8a7fb80> index path: (<NSIndexPath: 0x8a7db90> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionHeader); frame = (0 50; 320 50); zIndex = 1024;
without invalidating the layout'
It seems that this is caused by the update of the attributes, as if I comment out the following two lines it works fine:
attributes.zIndex = 1024;
attributes.frame = frame;
What is causing this error, and what can I do to get my simple example up and running?
Here is the full class implementation for this simple example:
@implementation myStackedHeaderFlowLayout
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
// Call super to get elements
NSMutableArray* answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
// As a test, always add first header to the answer array
NSArray* indexes = [NSArray arrayWithObjects: [NSNumber numberWithInt:0], nil];
for (NSNumber* sectionNumber in indexes) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:[sectionNumber integerValue]];
UICollectionViewLayoutAttributes* layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
if (layoutAttributes) {
[answer removeObject:layoutAttributes]; // remove if already present
[answer addObject:layoutAttributes];
}
}
return answer;
}
- (UICollectionViewLayoutAttributes*)layoutAttributesForSupplementaryViewOfKind:(NSString*)kind atIndexPath:(NSIndexPath*)indexPath {
// Call super to get base attributes
UICollectionViewLayoutAttributes* attributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
CGRect frame = attributes.frame;
frame.origin.y += 50;
// Update attributes position here - causes the problem
attributes.zIndex = 1024;
attributes.frame = frame;
}
return attributes;
}
- (UICollectionViewLayoutAttributes*)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString*)kind atIndexPath:(NSIndexPath*)indexPath {
UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
return attributes;
}
- (UICollectionViewLayoutAttributes*)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString*)kind atIndexPath:(NSIndexPath*)indexPath {
UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
return attributes;
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {
return YES;
}
@end
layout attributes for supplementary item at index path (<NSIndexPath>)
changed from <UICollectionViewLayoutAttributes>
to <UICollectionViewLayoutAttributes>
without invalidating the layout
In my experience, the NSInternalInconsistencyException
with the description above is thrown when the array returned from layoutAttributesForElementsInRect:
contains two UICollectionViewLayoutAttributes
objects with the same index path and (supplementary) element category.