I am using a UICollectionView with a custom layout that lays out cells in a grid format. There can be well over 50 rows and 50 columns. Scrolling occurs both vertically and horizontally. Currently, I am doing all of the layout setup in prepareLayout
and storing it in arrays:
- (void)prepareLayout {
NSMutableArray *newLayoutInfo = [[NSMutableArray alloc] init];
NSMutableArray *newLinearLayoutInfor = [[NSMutableArray alloc] init];
NSInteger sectionCount = [self.collectionView numberOfSections];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
self.heightForRows = [delegate collectionViewHeightForAllRows];
self.totalWidthsForRows = [[NSMutableArray alloc] init];
for (int i = 0; i < sectionCount; i++) {
[self.totalWidthsForRows addObject:[NSNumber numberWithInt:0]];
}
for (NSInteger section = 0; section < sectionCount; section++) {
NSMutableArray *cellLayoutInfo = [[NSMutableArray alloc] init];
NSInteger itemCount = [self.collectionView numberOfItemsInSection:section];
for (NSInteger item = 0; item < itemCount; item++) {
indexPath = [NSIndexPath indexPathForItem:item inSection:section];
UICollectionViewLayoutAttributes *itemAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
itemAttributes.frame = [self frameForCellAtIndexPath:indexPath];
[cellLayoutInfo addObject:itemAttributes];
[newLinearLayoutInfor addObject:itemAttributes];
}
[newLayoutInfo addObject:cellLayoutInfo];
}
self.layoutInfo = newLayoutInfo;
self.linearLayoutInfo = newLinearLayoutInfor;
}
Then in layoutAttributesForElementsInRect
I have:
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *rows = [self.linearLayoutInfo filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UICollectionViewLayoutAttributes *evaluatedObject, NSDictionary *bindings) {
return CGRectIntersectsRect(rect, [evaluatedObject frame]);
}]];
This works okay, but it is laggy and jumpy when I have over 50 columns and 50 rows. The problem I now have is that I must set
-(BOOL)shouldInvalidateLayoutForBoundsChange {
return YES;
}
This makes it prepare the entire layout every time the bounds change, which, needless to say, has a huge impact on performance and you can barely scroll. The cells consist of just text with an opaque background, so there is no issue there.
I am sure I am not doing this right and that there must be a better way. Thanks for the help in advance.
In custom flow layout I do this and it seems to help:
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return !(CGSizeEqualToSize(newBounds.size, self.collectionView.frame.size));
}
-(BOOL)shouldInvalidateLayoutForBoundsChange {
return YES;
}
Causes the layout to do prepareLayout()
every time it scrolls, which means anything of heavy computing in prepare will lead to a laggy practice, so one possible direction to solve this is to check what's really taking much time. One possibility is what's inside
for (NSInteger section = 0; section < sectionCount; section++)
{
// generate attributes ...
}
in order to generate attributes for the layout. Every time it scrolls, every time this generalization reruns, so that it impacts on the scroll appear to be jumpy and clumsy. So in order to solve this issue, or at least sort out that this is not the really trouble, I suggest setting a flag in this layout algorithm, say, isScrolling, standing for the situation where the layout needs to prepare. Every time in prepareLayout()
check the flag, if it is YES, then we'll know there's no need to do for loop to regenerate all the attributes, which alreay exsit ever since the first time the layout is initialised.
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