LoginSignup
6

More than 5 years have passed since last update.

UICollectionViewをPagingする1方法

Last updated at Posted at 2015-07-21

概要

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6