How can I detect when a UITableView
has been scrolled to the bottom so that the last cell is visible?
Asked
Active
Viewed 3.6k times
22

Bartłomiej Semańczyk
- 59,234
- 49
- 233
- 358

Ward
- 3,318
- 3
- 30
- 50
8 Answers
41
Inside tableView:cellForRowAtIndexPath:
or tableView:willDisplayCell:forRowAtIndexPath:
like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
NSInteger sectionsAmount = [tableView numberOfSections];
NSInteger rowsAmount = [tableView numberOfRowsInSection:[indexPath section]];
if ([indexPath section] == sectionsAmount - 1 && [indexPath row] == rowsAmount - 1) {
// This is the last cell in the table
}
...
}

Michael Kessler
- 14,245
- 13
- 50
- 64
-
you might as well have said I'm a dummy. thanks for the help sometimes I think these things are harder than they are. – Ward Jul 13 '10 at 22:16
-
3numberOfSections calls datasource numberOfSectionsInTableView and numberOfRowsInSection calls datasource numberOfRowsInSection. And in my implementation it got crashed showing this recursive log of this execution. – Naveen Shan Dec 11 '12 at 06:28
27
Implement the tableView:willDisplayCell:forRowAtIndexPath:
method in your UITableViewDelegate and check to see if it's the last row.

Art Gillespie
- 8,747
- 1
- 37
- 34
-
1thanks for the tip. I'm actually using this method to trigger an event and it looks like because it's "Will" display, it happens before it actually displays the cell. Is there a method that fires after the cell is displayed? – Ward Jul 14 '10 at 01:41
-
Alas, no. You could fudge a little by using `performSelector:withObject:afterDelay` with a very short delay to call a method that does what you need. – Art Gillespie Jul 14 '10 at 02:29
-
@ArtGillespie Found exactly what I was looking for. Cheers ! – dhamini poornachandra May 23 '17 at 12:51
-
willDisplay for last cell is called in my app at the beginning of tableview load data – Aji Saputra Raka Siwi Mar 10 '23 at 03:42
14
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger lastSectionIndex = [tableView numberOfSections] - 1;
NSInteger lastRowIndex = [tableView numberOfRowsInSection:lastSectionIndex] - 1;
if ((indexPath.section == lastSectionIndex) && (indexPath.row == lastRowIndex)) {
// This is the last cell
}
}

samwize
- 25,675
- 15
- 141
- 186
7
Create elegant extension for UITableView
:
extension UITableView {
func isLast(for indexPath: IndexPath) -> Bool {
let indexOfLastSection = numberOfSections > 0 ? numberOfSections - 1 : 0
let indexOfLastRowInLastSection = numberOfRows(inSection: indexOfLastSection) - 1
return indexPath.section == indexOfLastSection && indexPath.row == indexOfLastRowInLastSection
}
}
Example of usage:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView.isLast(for: indexPath) {
//do anything then
}
return cell
}

Bartłomiej Semańczyk
- 59,234
- 49
- 233
- 358
4
Swift 5+
//Show Last Cell (for Table View)
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
if indexPath.row == (yourdataArray.count - 1)
{
print("came to last row")
}
}
//Show last cell (for Collection View)
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath)
{
if indexPath.row == (yourdataArray.count - 1)
{
// Last cell is visible
}
}

Shakeel Ahmed
- 5,361
- 1
- 43
- 34
-
How do you do it if instead of indexPath.row using indexPath.section? My app has a lot of sections and I would like it to detect when the user scroll to the last section. – 14079_Z Apr 09 '20 at 07:42
-
-
Can it works on the multiple sections but each sections only have 1-2 row? – 14079_Z Apr 09 '20 at 20:42
-
yes its is very easy just use this code in your mention section and done – Shakeel Ahmed Apr 11 '20 at 13:36
3
For Xcode 8 and swift 3
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let lastSectionIndex = tableView.numberOfSections - 1
let lastRowIndex = tableView.numberOfRows(inSection: lastSectionIndex) - 1
if indexPath.section == lastSectionIndex && indexPath.row == lastRowIndex {
print("this is the last cell")
}
}

shafi
- 426
- 3
- 15
1
I found this solution:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let contentOffsetMaxY: Float = Float(scrollView.contentOffset.y + scrollView.bounds.size.height)
let contentHeight: Float = Float(scrollView.contentSize.height)
let lastCellIsVisible = contentOffsetMaxY > contentHeight + somePaddingIfWanted
if lastCellIsVisible {
doSomething()
}
}

Luchi Parejo Alcazar
- 121
- 6
0
I had some problems with the willDisplayCell method. This works for me:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let y = scrollView.contentOffset.y/(scrollView.contentSize.height - scrollView.frame.size.height)
let relativeHeight = 1 - (table.rowHeight / (scrollView.contentSize.height - scrollView.frame.size.height))
if y >= relativeHeight{
print("last cell is visible")
}
}
Just pass this in the delegate methods, and change 'table' to your tableView.

J. Doe
- 12,159
- 9
- 60
- 114