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
.
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
}
}
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With