Search code examples
iosswiftuicollectionviewuicollectionviewcellnsindexpath

Get the indexPath of cell in the center of collectionView in swift?


I have tried this to get the index of a cell in the center of a collection view by using an extension of uicollectionview, but I always get nil instead of the index. How can I fix this?

extension UICollectionView {
    var centerPoint : CGPoint {
        get {
            return CGPoint(x: self.center.x + self.contentOffset.x, y: self.center.y + self.contentOffset.y);
        }
    }

    var centerCellIndexPath: NSIndexPath? {
        if let centerIndexPath: NSIndexPath  = self.indexPathForItemAtPoint(self.centerPoint) {
            return centerIndexPath
        }

        return nil
    }
}

then: in a UIViewController in a random method I have this:

if let centerCellIndexPath: NSIndexPath  = collectionTemp!.centerCellIndexPath {
    print(centerCellIndexPath)
} else {
    println("nil")
}

the index path is always nil, and I don't get it why, because the cells display in order, everything is fine except this.


Solution

  • I've managed to solve my problem by using a custom layout that always keeps a cell in the center. Using this the indexPath in the center can never be nil.

     class CenterFlowLayout: UICollectionViewFlowLayout {
    
     override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
         if let cv = self.collectionView {
            let cvBounds = cv.bounds
            let halfWidth = cvBounds.size.width * 0.5
            let proposedContentOffsetCenterX = proposedContentOffset.x + halfWidth
         if let attributesForVisibleCells = self.layoutAttributesForElementsInRect(cvBounds) as [UICollectionViewLayoutAttributes]! {
            var candidateAttributes: UICollectionViewLayoutAttributes?
            for attributes in attributesForVisibleCells {
          // == Skip comparison with non-cell items (headers and footers) == //
          if attributes.representedElementCategory != UICollectionElementCategory.Cell {
            continue
          }
          if let candAttrs = candidateAttributes {
            let a = attributes.center.x - proposedContentOffsetCenterX
            let b = candAttrs.center.x - proposedContentOffsetCenterX
                if fabsf(Float(a)) < fabsf(Float(b)) {
                   candidateAttributes = attributes
                }
          } else { // == First time in the loop == //
            candidateAttributes = attributes
            continue
          }
        }
        return CGPoint(x : candidateAttributes!.center.x - halfWidth, y : proposedContentOffset.y)
      }
    }
    // Fallback
        return super.targetContentOffsetForProposedContentOffset(proposedContentOffset)
     }
    }
    

    Add this as the subclass of the UICollectionFlowLayout.