UICollectionViewで横スクロールページングのインデックス取得

UICollectionViewでシンプルなページングする横スクロール画面を実装した時に、何番目のセルを表示中か取得しようとしたらうまくいかない状況があったのでほぼメモ。

// Before
- (NSInteger)visibleIndex {
    NSInteger index = NSNotFound;
    NSArray<NSIndexPath *> *indexPaths = [self.collectionView indexPathsForVisibleItems];
    NSIndexPath *indexPath = [indexPaths firstObject];
    if (indexPath) {
        index = indexPath.row;
    }
    return index;
}

// After
- (NSInteger)visibleIndex {
    NSInteger index = NSNotFound;
    NSArray<NSIndexPath *> *indexPaths = [self.collectionView indexPathsForVisibleItems];
    if (indexPaths.count > 0) {
        CGFloat offsetX = self.collectionView.contentOffset.x;
        CGFloat width = CGRectGetWidth(self.collectionView.frame);
        index = floor(offsetX / width);
    }
    return index;
}

はじめはこんな風に表示中のindexPathの配列を取得して、オブジェクト1つとり出せばいいかなと思っていました。

NSArray<NSIndexPath *> *indexPaths = [self.collectionView indexPathsForVisibleItems];
NSIndexPath *indexPath = [indexPaths firstObject];

実際にスクロールさせてみると、ページング直後に [self.collectionView indexPathsForVisibleItems] を呼ぶと複数のNSIndexPathが返ってくる場合がありました。

仕方が無いのでNSIndexPathはセルを表示中という判定にだけ使用して、あとはUIScrollViewでよくある[UIScrollView contentOffset]から位置を算出する方法で対応しました。

NSArray<NSIndexPath *> *indexPaths = [self.collectionView indexPathsForVisibleItems];
if (indexPaths.count > 0) {
    CGFloat offsetX = self.collectionView.contentOffset.x;
    CGFloat width = CGRectGetWidth(self.collectionView.frame);
    index = floor(offsetX / width);
}

UICollectionViewはあえて使う必要が無い場合が多いと思っているので、正直あんまり使い方をわかっていないです。