Edited at

UICollectionViewをPagingする1方法

More than 3 years have passed since last update.


概要

UICollectionviewをpagingEnable = trueでPage間のセルの位置ズレを発生させないでPagingする方法の紹介です。

スクリーンショット 2015-07-22 1.49.11.png

スクリーンショット 2015-07-22 1.49.14.png


現状の問題点

ページングしていくと、初期位置が少しずつずれていく(下図参照)。

image0.png

image1.png


制限事項

1セクションのみ対応です。


対応方法

UICollectionFlowLayoutクラスを継承したクラス内で毎回、layout処理を

行う。

処理の流れは以下

1)cellサイズを取得する。

2)表示ウインドウ内に収まるrow、column数を算出する。

3)x, y軸方向マージンを計算する。

x軸方向マージン = {コンテントサイズ.width - (cell幅 * column数) - (columnCont > 1 ? (columnCont - 1)*minimumLineSpacing}/2.0

y軸方向マージン = {コンテントサイズ.height - (cell高 * row数) - (rowCount > 1 ? (rowCount - 1) * minimumInteritemSpacing}/2.0

4)ページ毎indexを計算する。

index = セルindex%(rowCount*columnCount)

ページ内のrow,col番号 2行3列という感じで

row = index%rowCount

col = index/rowCount

5)配置位置を計算してCGRectでセットする。

6)ページング量を計算してorigin.xにセットする。

実装は以下

private func frameForItemAtIndexPath(indexPath: NSIndexPath) -> CGRect {

// 1)
let canvasSize = self.collectionView?.frame.size ?? CGSizeZero
// 2)
let rowCount = floor((canvasSize.height - self.sectionInset.top - self.sectionInset.bottom) / (self.itemSize.height + self.minimumInteritemSpacing))
let columnCont = floor((canvasSize.width - self.sectionInset.left - self.sectionInset.right) / (self.itemSize.width + self.minimumLineSpacing))
// 3)
let pageMarginX = (canvasSize.width - columnCont * self.itemSize.width - (columnCont > 1 ? (columnCont - 1) * self.minimumLineSpacing : 0)) / 2.0
let pageMarginY = (canvasSize.height - rowCount * self.itemSize.height - (rowCount > 1 ? (rowCount - 1) * self.minimumInteritemSpacing : 0)) / 2.0
// 4)
let pageIndex = indexPath.row%Int(rowCount * columnCont)
let row = pageIndex % Int(rowCount)
let column = pageIndex / Int(rowCount)
// 5)
var cellFrame = CGRectZero
cellFrame.origin.x = pageMarginX + CGFloat(column) * (self.itemSize.width + self.minimumLineSpacing)
cellFrame.origin.y = pageMarginY + CGFloat(row) * (self.itemSize.height + self.minimumInteritemSpacing)
cellFrame.size.width = self.itemSize.width
cellFrame.size.height = self.itemSize.height
// 6)
if (self.scrollDirection == UICollectionViewScrollDirection.Horizontal) {
let page = floor(CGFloat(indexPath.row)/(rowCount * columnCont))
cellFrame.origin.x += canvasSize.width * page
}

return cellFrame
}

override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {

let attr = super.layoutAttributesForItemAtIndexPath(indexPath)
attr.frame = self.frameForItemAtIndexPath(indexPath)
return attr
}

override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
var attrs = [AnyObject]()
if let originAttrs = super.layoutAttributesForElementsInRect(rect) {
for var index = 0; index < self.collectionView?.numberOfItemsInSection(0); index++ {
let indexPath = NSIndexPath(forRow: index, inSection: 0)
let itemFrame = self.frameForItemAtIndexPath(indexPath)
if CGRectIntersectsRect(itemFrame, rect) {
let attr = self.layoutAttributesForItemAtIndexPath(indexPath)
attrs.append(attr)
}
}
}
return attrs
}

ソースコードはこちら


参考サイト

UICollectionView align logic missing in horizontal paging scrollview