I've got a UICollectionView
, which works ok, until I start scrolling. Here some pics first:
As you can see it's great. As I start scrolling (paging enabled) the first one goes a bit offscreen:
This is the problem. Originaly my view have 3 views and I want to scroll and show 3 views only. But as it scrolls (paging enabled) it hides a little bit of the first view and show little bit of the next first view from the next page.
And here is a video, because it's kinda hard to explain: Video of the problem (Dropbox)
Here is a picture of my UICollectionView
settings:
It's going to be great if someone can help!
The fundamental issue is Flow Layout is not designed to support the paging. To achieve the paging effect, you will have to sacrifice the space between cells. And carefully calculate the cells frame and make it can be divided by the collection view frame without remainders. I will explain the reason.
Saying the following layout is what you wanted.
Notice, the most left margin (green) is not part of the cell spacing. It is determined by the flow layout section inset. Since flow layout doesn't support heterogeneous spacing value. It is not a trivial task.
Therefore, after setting the spacing and inset. The following layout is what you will get.
After scroll to next page. Your cells are obviously not aligned as what you expected.
Making the cell spacing 0 can solve this issue. However, it limits your design if you want the extra margin on the page, especially if the margin is different from the cell spacing. It also requires the view frame must be divisible by the cell frame. Sometimes, it is a pain if your view frame is not fixed (considering the rotation case).
- (CGSize)collectionViewContentSize { // Only support single section for now. // Only support Horizontal scroll NSUInteger count = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:0]; CGSize canvasSize = self.collectionView.frame.size; CGSize contentSize = canvasSize; if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal) { NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1; NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1; NSUInteger page = ceilf((CGFloat)count / (CGFloat)(rowCount * columnCount)); contentSize.width = page * canvasSize.width; } return contentSize; } - (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath { CGSize canvasSize = self.collectionView.frame.size; NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1; NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1; CGFloat pageMarginX = (canvasSize.width - columnCount * self.itemSize.width - (columnCount > 1 ? (columnCount - 1) * self.minimumLineSpacing : 0)) / 2.0f; CGFloat pageMarginY = (canvasSize.height - rowCount * self.itemSize.height - (rowCount > 1 ? (rowCount - 1) * self.minimumInteritemSpacing : 0)) / 2.0f; NSUInteger page = indexPath.row / (rowCount * columnCount); NSUInteger remainder = indexPath.row - page * (rowCount * columnCount); NSUInteger row = remainder / columnCount; NSUInteger column = remainder - row * columnCount; CGRect cellFrame = CGRectZero; cellFrame.origin.x = pageMarginX + column * (self.itemSize.width + self.minimumLineSpacing); cellFrame.origin.y = pageMarginY + row * (self.itemSize.height + self.minimumInteritemSpacing); cellFrame.size.width = self.itemSize.width; cellFrame.size.height = self.itemSize.height; if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal) { cellFrame.origin.x += page * canvasSize.width; } return cellFrame; } - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewLayoutAttributes * attr = [super layoutAttributesForItemAtIndexPath:indexPath]; attr.frame = [self frameForItemAtIndexPath:indexPath]; return attr; } - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect]; NSMutableArray * attrs = [NSMutableArray array]; [originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) { NSIndexPath * idxPath = attr.indexPath; CGRect itemFrame = [self frameForItemAtIndexPath:idxPath]; if (CGRectIntersectsRect(itemFrame, rect)) { attr = [self layoutAttributesForItemAtIndexPath:idxPath]; [attrs addObject:attr]; } }]; return attrs; }
Notice, above code snippet only supports single section and horizontal scroll direction. But it is not hard to expand.
Also, if you don't have millions of cells. Caching those UICollectionViewLayoutAttributes may be a good idea.
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