はじめに
iOS Second Stage Advent Calendar 13日目の記事です。
今回で4記事目です。
宜しくお願いします。
本題
タイトル通り、無限スクロールするUICollectionView
です。
なんかGIFが載せられないので後日載せます。
プロジェクトは以下にあるので、興味ある方はみてください。
AdventCalendar2015/SampleInfinityCollectionView at master · ryokosuge/AdventCalendar2015
ちょっとした解説
UICollectionView
のlayoutSubviews()
でちょっと手を加えてます。
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
を使うみたいにやりたかったのですが、UICollectionView
のdelegate
とかdataSource
とかをOverrideするやり方が Swiftだとわかりませんでした...。
どなたかやり方とかURLとか教えてもらえるとすごく嬉しいです。
オープンソース、見てみます。
終わりに
できることの知見を残しておきたいなと思い、色々サンプルを作っています。
結構サンプル作るの楽しいです。
おかげでGitHubにも草が生えてきました。
以上です。