LoginSignup
32
32

More than 5 years have passed since last update.

【iOS】無限スクロールするUICollectionViewの作り方

Posted at

はじめに

iOS Second Stage Advent Calendar 13日目の記事です。

今回で4記事目です。

宜しくお願いします。

本題

タイトル通り、無限スクロールするUICollectionViewです。

SampleInfinityCollectionView.gif

なんかGIFが載せられないので後日載せます。

プロジェクトは以下にあるので、興味ある方はみてください。

AdventCalendar2015/SampleInfinityCollectionView at master · ryokosuge/AdventCalendar2015

ちょっとした解説

UICollectionViewlayoutSubviews()でちょっと手を加えてます。

InfinityCollectionView.swift
import UIKit

class InfinityCollectionView: UICollectionView {

    /// 表示するCellの数を増大させる比率
    var factor: Int = 1
    private var needsScrollToCenter: Bool = true

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        layoutRecenter()

        if contentSize.width > 0.0 && needsScrollToCenter {
            var i: Int = 0
            var x: CGFloat = 0.0
            while i <= 0 {
                let indexPath = NSIndexPath(forItem: i, inSection: 0)
                guard let attribute = collectionViewLayout.layoutAttributesForItemAtIndexPath(indexPath) else {
                    break
                }
                var minimumInteritemSpacing: CGFloat = 0.0
                if let delegateFlowLayout = delegate as? UICollectionViewDelegateFlowLayout {
                    minimumInteritemSpacing = delegateFlowLayout.collectionView?(self, layout: self.collectionViewLayout, minimumInteritemSpacingForSectionAtIndex: 0) ?? 0.0
                } else if let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout {
                    minimumInteritemSpacing = flowLayout.minimumInteritemSpacing
                }
                x += attribute.bounds.width - (minimumInteritemSpacing * 2)
                i++
            }
            setContentOffset(CGPoint(x: contentOffset.x - x, y: 0), animated: false)
            needsScrollToCenter = false
        }

    }
}

extension InfinityCollectionView {

    private func layoutRecenter() {
        let currentOffset = contentOffset
        let contentWidth = contentSize.width
        let centerOffsetX = contentWidth / 2.0

        let distanceFromCenterX = fabs(currentOffset.x - centerOffsetX)

        let allCellWidth = CGFloat(contentWidth / CGFloat(factor))
        if distanceFromCenterX > allCellWidth {
            let offset = CGFloat(fmodf(Float(currentOffset.x - centerOffsetX), Float(allCellWidth)))
            contentOffset = CGPoint(x: centerOffsetX + offset, y: currentOffset.y)
        }
    }

}

要はscrollOffsetの値が真ん中以上だったらちょっと同じ要素のCellの位置までOffsetを戻して更新しているという感じです。

すごくシンプルな話なので、深く考えなくて大丈夫かと思います。

疑問

できれば普通にUICollectionViewを使うみたいにやりたかったのですが、UICollectionViewdelegateとかdataSourceとかをOverrideするやり方が Swiftだとわかりませんでした...。

どなたかやり方とかURLとか教えてもらえるとすごく嬉しいです。

オープンソース、見てみます。

終わりに

できることの知見を残しておきたいなと思い、色々サンプルを作っています。

結構サンプル作るの楽しいです。

おかげでGitHubにも草が生えてきました。

以上です。

32
32
1

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
32
32