基本的な問題は、Flow Layout がページングをサポートするように設計されていないことです。ページング効果を実現するには、セル間のスペースを犠牲にする必要があります。そして、セルフレームを慎重に計算し、コレクションビューフレームで余りなく分割できるようにします。その理由を説明します。
次のレイアウトを言うと、あなたが望んでいたものです。
一番左の余白 (緑) はセル間隔の一部ではないことに注意してください。これは、フロー レイアウト セクション インセットによって決まります。フロー レイアウトは異種の間隔値をサポートしていないためです。これは簡単な作業ではありません。
したがって、間隔とインセットを設定した後。次のレイアウトが得られます。
次のページにスクロールした後。あなたの細胞は明らかにあなたが期待したように整列していません.
セル間隔を 0 にすると、この問題を解決できます。ただし、ページに余分な余白が必要な場合、特に余白がセルの間隔と異なる場合は、デザインが制限されます。また、ビュー フレームがセル フレームで割り切れる必要があります。ビュー フレームが固定されていないと (回転の場合を考えると) 面倒な場合があります。
本当の解決策は、UICollectionViewFlowLayout をサブクラス化し、次のメソッドをオーバーライドすることです
- (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;
}
上記のコード スニペットは、単一セクションと水平スクロール方向のみをサポートしていることに注意してください。しかし、展開するのは難しくありません。
また、数百万のセルがない場合。これらの UICollectionViewLayoutAttributes をキャッシュすることをお勧めします。