Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if last cell is visible in UICollectionView?

I am trying to detect if the last cell in a collectionView is visible.

var isLastCellVisible: Bool {

    let lastIndexPath = NSIndexPath(forItem: self.messages.count - 1, inSection: 0)
    let visibleIndexPaths = self.collectionView.indexPathsForVisibleItems()

    let lastCellPositionY = self.collectionView.layoutAttributesForItemAtIndexPath(lastIndexPath)!.frame.origin.y
    let bottomInset = self.collectionView.contentInset.bottom // changes when the keyboard is shown / hidden
    let contentHeight = self.collectionView.contentSize.height

    if visibleIndexPaths.contains(lastIndexPath) && (contentHeight - lastCellPositionY) > bottomInset {
        return true
    } else {
        return false
    }
}

What works:

If the last cell is visible and the keyboard is shown so that the cell is not hidden by it, the above code returns true. If it is hidden it returns false.

But I can't figure out how to return true, when the user scrolls up and the last cell is above the keyboard.

lastCellPositionY and contentHeight don't change when the collectionView gets scrolled up. Instead self.collectionView.bounds.origin.y does change, but I don't know how to compare lastCellPositionY to it, since they don't share the same origin and self.collectionView.bounds.origin.y is significantly less than lastCellPositionY.

like image 750
MJQZ1347 Avatar asked Jun 18 '16 14:06

MJQZ1347


2 Answers

What i am using

override func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
        if indexPath.row == dataSource.count - 1 {
            // Last cell is visible
        }
    }
like image 152
Gaurav Pandey Avatar answered Sep 28 '22 08:09

Gaurav Pandey


An handy extension with two computed properties for this.

extension UICollectionView {

    var isLastItemFullyVisible: Bool {

        let numberOfItems = numberOfItems(inSection: 0)
        let lastIndexPath = IndexPath(item: numberOfItems - 1, section: 0)

        guard let attrs = collectionViewLayout.layoutAttributesForItem(at: lastIndexPath) 
        else { 
            return false 
        }
        return bounds.contains(attrs.frame)
    }

    // If you don't care if it's fully visible, as long as some of it is visible
    var isLastItemVisible: Bool {
       let numberOfItems = collectionView.numberOfItems(inSection: 0)
       return indexPathsForVisibleItems.contains(where: { $0.item == numberOfItems - 1 })
    }
}

There's an alternative to the isLastItemFullyVisible. A one liner.

var isLastItemFullyVisible: Bool {
   contentSize.width == contentOffset.x + frame.width - contentInset.right
}
like image 38
Nuno Gonçalves Avatar answered Sep 28 '22 07:09

Nuno Gonçalves