22

How can I detect when a UITableView has been scrolled to the bottom so that the last cell is visible?

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
Ward
  • 3,318
  • 3
  • 30
  • 50

8 Answers8

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
  • 3
    numberOfSections 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
  • 1
    thanks 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
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()
      }
}
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