Reputation: 59
I've got a fairly standard grid layout using a subclass of UICollectionViewFlowLayout
. When the user taps a cell I move the cells in the subsequent rows down to make space for a detail view that will appear. It looks like this:
In that detail view I want to show another view with related data, similar to how iTunes shows album details. The existing layout has headers for each section and I'm currently slapping the detail view into place, manually managing the frame's position. This gets tricky with rotations and cells moving around.
How can I convince the layout to handle the detail's position by treating it as a supplementary view? My controller is configured correctly to display the detail as a supplementary view, same for the layout.
Upvotes: 1
Views: 689
Reputation: 59
Solved the problem. In broad strokes, here's what works for me:
UICollectionViewLayoutAttributes
and register it in your layout by overriding the layoutAttributesClass
function. layoutAttributesForElementsInRect:
retrieve all standard layout attributes with [super layoutAttributesForElementsInRect:rect];
.[attributesCopy addObject:[self layoutAttributesForSupplementaryViewOfKind:YourSupplementaryKind atIndexPath:indexPathForTappedCell]];
layoutAttributesForSupplementaryViewOfKind:atIndexPath:
get the attributes for your view with something like
YourLayoutAttributes *attributes = [YourLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind withIndexPath:indexPath];
elementKind
matches the type of supplementary view you want to generate[self layoutAttributesForItemAtIndexPath:indexPath];
The important part to note is you can't skip subclassing UICollectionViewLayoutAttributes
. Doing asking super
(a UICollectionViewFlowLayout
instance) for attributes of a supplemental view for anything but standard header or footers will return nil
. I couldn't find any concrete documentation on this behavior so I might be wrong but in my experience it was the subclassed attributes that solved my problems.
Your code should look something like this:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *allAttributesInRect = [super layoutAttributesForElementsInRect:rect];
NSMutableArray *attributes = NSMutableArray.array;
for (UICollectionViewLayoutAttributes *cellAttributes in allAttributesInRect)
{
// Do things with regular cells and supplemental views
}
if (self.selectedCellPath)
{
UICollectionViewLayoutAttributes *detailAttributes = [self layoutAttributesForSupplementaryViewOfKind:SomeLayoutSupplimentaryDetailView atIndexPath:self.selectedCellPath];
[attributes addObject:detailAttributes];
}
return attributes.copy;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
{
SomeLayoutAttributes *attributes = [SomeLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind withIndexPath:indexPath];
if ([elementKind isEqualToString:SomeLayoutSupplimentaryDetailView])
{
UICollectionViewLayoutAttributes *cellAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
CGRect frame = cellAttributes.frame;
frame.size.width = CGRectGetWidth(self.collectionView.frame); // or whatever works for you
attributes.frame = frame;
}
return attributes;
}
Your UICollectionViewLayoutAttributes
subclass doesn't necessarily need any extra properties or functions but it's a great place to store data specific to that view for configuration use after you retrieve the view using dequeueReusableSupplementaryViewOfKind:forIndexPath:
.
Upvotes: 2