UICollectionView current visible cell index

I am using UICollectionView first time in my iPad application.
I have set UICollectionView such that its size and cell size is same, means only once cell is displayed at a time.

Problem:
Now when user scroll UICollectionView I need to know which cell is visible I have to update other UI elements on change. I didn’t find any delegate method for this. How can I achieve this?

  • How to add multiple UIImageViews to paging UIScrollView?
  • How to make app fully working correctly for autorotation in iOS 6?
  • How to create a UIImage from the current graphics context?
  • Unable to trim a video using AVAssetExportSession
  • How to compile OpenCV for iOS7 (arm64)
  • How to call didSelectRowAtIndexPath before prepareForSegue?
  • Code:

    [self.mainImageCollection setTag:MAIN_IMAGE_COLLECTION_VIEW];
    [self.mainImageCollection registerClass:[InspirationMainImageCollectionCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
    [self.mainImageFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    [self.mainImageFlowLayout setMinimumInteritemSpacing:0.0f];
    [self.mainImageFlowLayout setMinimumLineSpacing:0.0f];
    self.mainImageFlowLayout.minimumLineSpacing = 0;
    [self.mainImageCollection setPagingEnabled:YES];
    [self.mainImageCollection setShowsHorizontalScrollIndicator:NO];
    [self.mainImageCollection setCollectionViewLayout:self.mainImageFlowLayout];
    

    What I have tried:

    As UICollectionView Conforms to UIScrollView, I got when user scroll ends with UIScrollViewDelegate method

    -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    

    But inside above function how can I get current visible cell index of UICollectionView ???

    13 Solutions Collect From Internet About “UICollectionView current visible cell index”

    The method [collectionView visibleCells] give you all visibleCells array you want. Use it when you want to get

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
        for (UICollectionViewCell *cell in [self.mainImageCollection visibleCells]) {
            NSIndexPath *indexPath = [self.mainImageCollection indexPathForCell:cell];
            NSLog(@"%@",indexPath);
        }
    }
    

    indexPathsForVisibleItems might work for most situations, but sometimes it returns an array with more than one index path and it can be tricky figuring out the one you want. In those situations, you can do something like this:

    CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
    CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
    NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];
    

    This works especially well when each item in your collection view takes up the whole screen.

    Working Answers Combined In Swift 2.2 :

     func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    
            var visibleRect = CGRect()
    
            visibleRect.origin = self.collectionView.contentOffset
            visibleRect.size = self.collectionView.bounds.size
    
            let visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect))
    
            let visibleIndexPath: NSIndexPath = self.collectionView.indexPathForItemAtPoint(visiblePoint)!
    
            print(visibleIndexPath)
    
        }
    

    In Swift 3:

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        var visibleRect = CGRect()
    
        visibleRect.origin = collectionView.contentOffset
        visibleRect.size = collectionView.bounds.size
    
        let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
    
        let visibleIndexPath: IndexPath = collectionView.indexPathForItem(at: visiblePoint)!
    
        print(visibleIndexPath)
    }
    

    For completeness sake, this is the method that ended up working for me. It was a combination of @Anthony & @iAn’s methods.

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
          CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
          CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
          NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];
          NSLog(@"%@",visibleIndexPath);
    }
    

    Just want to add for others :
    for some reason, I didnt not get the cell that was visible to the user when I was scrolling to previous cell in collectionView with pagingEnabled.

    So I insert the code inside dispatch_async to give it some “air”
    and this works for me.

    -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        dispatch_async(dispatch_get_main_queue(), ^{
                UICollectionViewCell * visibleCell= [[self.collectionView visibleCells] objectAtIndex:0];
    
    
                [visibleCell doSomthing];
            });
    }
    

    It will probably be best to use UICollectionViewDelegate methods: (Swift 3)

    // Called before the cell is displayed    
    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        print(indexPath.row)
    }
    
    // Called when the cell is displayed
    func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        print(indexPath.row)
    }
    

    For Swift 3.0

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let visibleRect = CGRect(origin: colView.contentOffset, size: colView.bounds.size)
        let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
        let indexPath = colView.indexPathForItem(at: visiblePoint)
    }
    

    You can use scrollViewDidEndDecelerating: for this

    //@property (strong, nonatomic) IBOutlet UICollectionView *collectionView;
    
       - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    
            for (UICollectionViewCell *cell in [self.collectionView visibleCells]) {
                NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
                NSUInteger lastIndex = [indexPath indexAtPosition:[indexPath length] - 1];
                NSLog(@"visible cell value %d",lastIndex);
            }
    
        }
    

    UICollectionView current visible cell index: Swift 3

    var visibleCurrentCell: IndexPath? {
        for cell in self.collectionView.visibleCells {
            let indexPath = self.collectionView.indexPath(for: cell)
            return indexPath
         }
    
         return nil
    }
    

    Swift 3.0

    Simplest solution which will give you indexPath for visible cells..

    yourCollectionView.indexPathsForVisibleItems 
    

    will return the array of indexpath.

    Just take the first object from array like this.

    yourCollectionView.indexPathsForVisibleItems.first
    

    I guess it should work fine with Objective – C as well.

    This is old question but in my case…

    - (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    
        _m_offsetIdx = [m_cv indexPathForCell:m_cv.visibleCells.firstObject].row;
    }
    
    - (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
        _m_offsetIdx = [m_cv indexPathForCell:m_cv.visibleCells.lastObject].row;
    }
    

    converting @Anthony’s answer to Swift 3.0 worked perfectly for me:

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
        var visibleRect = CGRect()
        visibleRect.origin = yourCollectionView.contentOffset
        visibleRect.size = yourCollectionView.bounds.size
        let visiblePoint = CGPoint(x: CGFloat(visibleRect.midX), y: CGFloat(visibleRect.midY))
        let visibleIndexPath: IndexPath? = yourCollectionView.indexPathForItem(at: visiblePoint)
        print("Visible cell's index is : \(visibleIndexPath?.row)!")
    }
    

    try this, it works. (in the example below i have 3 cells for example.)

        func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
        let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
        let visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect))
        let visibleIndexPath = self.collectionView.indexPathForItemAtPoint(visiblePoint)
        if let v = visibleIndexPath {
            switch v.item {
            case 0: setImageDescription()
                break
            case 1: setImageConditions()
                break
            case 2: setImageResults()
                break
            default: break
            }
        }