How to know when UITableView did scroll to bottom in iPhone?

IosUitableviewScroll

Ios Problem Overview


I would like to know when a UITableView did scroll to bottom in order to load and show more content, something like a delegate or something else to let the controller know when the table did scroll to bottom.

How can I do this?

Ios Solutions


Solution 1 - Ios

in the tableview delegate do something like this

ObjC:

- (void)scrollViewDidScroll:(UIScrollView *)aScrollView {
	CGPoint offset = aScrollView.contentOffset;
	CGRect bounds = aScrollView.bounds;
	CGSize size = aScrollView.contentSize;
	UIEdgeInsets inset = aScrollView.contentInset;
	float y = offset.y + bounds.size.height - inset.bottom;
	float h = size.height;
	// NSLog(@"offset: %f", offset.y);   
	// NSLog(@"content.height: %f", size.height);   
	// NSLog(@"bounds.height: %f", bounds.size.height);   
	// NSLog(@"inset.top: %f", inset.top);   
	// NSLog(@"inset.bottom: %f", inset.bottom);   
	// NSLog(@"pos: %f of %f", y, h);
	
	float reload_distance = 10;
	if(y > h + reload_distance) {
		NSLog(@"load more rows");
	}
}

Swift:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let offset = scrollView.contentOffset
    let bounds = scrollView.bounds
    let size = scrollView.contentSize
    let inset = scrollView.contentInset
    let y = offset.y + bounds.size.height - inset.bottom
    let h = size.height
    let reload_distance:CGFloat = 10.0
    if y > (h + reload_distance) {
        print("load more rows")
    }
}

Solution 2 - Ios

Modified neoneyes answer a bit.

This answer targets those of you who only wants the event to be triggered once per release of the finger.

Suitable when loading more content from some content provider (web service, core data etc). Note that this approach does not respect the response time from your web service.

- (void)scrollViewDidEndDragging:(UIScrollView *)aScrollView
                  willDecelerate:(BOOL)decelerate
{
    CGPoint offset = aScrollView.contentOffset;
    CGRect bounds = aScrollView.bounds;
    CGSize size = aScrollView.contentSize;
    UIEdgeInsets inset = aScrollView.contentInset;
    float y = offset.y + bounds.size.height - inset.bottom;
    float h = size.height;
    
    float reload_distance = 50;
    if(y > h + reload_distance) {
        NSLog(@"load more rows");
    }
}

Solution 3 - Ios

add this method in the UITableViewDelegate:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{   
    CGFloat height = scrollView.frame.size.height;
    
    CGFloat contentYoffset = scrollView.contentOffset.y;
    
    CGFloat distanceFromBottom = scrollView.contentSize.height - contentYoffset;
    
    if(distanceFromBottom < height) 
    {
        NSLog(@"end of the table");
    }
}

Solution 4 - Ios

None of the answers above helped me, so I came up with this:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)aScrollView
{   
    NSArray *visibleRows = [self.tableView visibleCells];
    UITableViewCell *lastVisibleCell = [visibleRows lastObject];
    NSIndexPath *path = [self.tableView indexPathForCell:lastVisibleCell];
    if(path.section == lastSection && path.row == lastRow)
    {
        // Do something here
    }
}

Solution 5 - Ios

The best way is to test a point at the bottom of the screen and use this method call when ever the user scrolls (scrollViewDidScroll):

- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point

Test a point near the bottom of the screen, and then using the indexPath it returns check if that indexPath is the last row then if it is, add rows.

Solution 6 - Ios

Use ā€“ tableView:willDisplayCell:forRowAtIndexPath: (UITableViewDelegate method)

Simply compare the indexPath with the items in your data array (or whatever data source you use for your table view) to figure out if the last element is being displayed.

Docs: http://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:willDisplayCell:forRowAtIndexPath:

Solution 7 - Ios

UITableView is a subclass of UIScrollView, and UITableViewDelegate conforms to UIScrollViewDelegate. So the delegate you attach to the table view will get events such as scrollViewDidScroll:, and you can call methods such as contentOffset on the table view to find the scroll position.

Solution 8 - Ios

NSLog(@"%f / %f",tableView.contentOffset.y, tableView.contentSize.height - tableView.frame.size.height);
    
if (tableView.contentOffset.y == tableView.contentSize.height - tableView.frame.size.height)
        [self doSomething];

Nice and simple

Solution 9 - Ios

in Swift you can do something like this. Following condition will be true every time you reach end of the tableview

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        if indexPath.row+1 == postArray.count {
            println("came to last row")
        }
}

Solution 10 - Ios

Building on @Jay Mayu's answer, which I felt was one of the better solutions:

Objective-C

// UITableViewDelegate
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

// Need to call the service & update the array
if(indexPath.row + 1 == self.sourceArray.count) {
    DLog(@"Displayed the last row!");
  }
}

Swift 2.x

// UITableViewDelegate
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    if (indexPath.row + 1) == sourceArray.count {
        print("Displayed the last row!")
    }
}

Solution 11 - Ios

Here is the swift 3.0 version code.

   func scrollViewDidScroll(_ scrollView: UIScrollView) {
        
        let offset = scrollView.contentOffset
        let bounds = scrollView.bounds
        let size = scrollView.contentSize
        let inset = scrollView.contentInset
        let y: Float = Float(offset.y) + Float(bounds.size.height) + Float(inset.bottom)
        let height: Float = Float(size.height)
        let distance: Float = 10
                    
        if y > height + distance {
            // load more data
        }
    }
     

Solution 12 - Ios

I generally use this to load more data , when last cell starts display

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   if (indexPath.row ==  myDataArray.count-1) {
        NSLog(@"load more");
    }
}

Solution 13 - Ios

Taking neoneye excellent answers but in swift, and renaming of the variables..

Basically we know we have reached the bottom of the table view if the yOffsetAtBottom is beyond the table content height.

func isTableViewScrolledToBottom() -> Bool {
    let tableHeight = tableView.bounds.size.height
    let contentHeight = tableView.contentSize.height
    let insetHeight = tableView.contentInset.bottom
    
    let yOffset = tableView.contentOffset.y
    let yOffsetAtBottom = yOffset + tableHeight - insetHeight
    
    return yOffsetAtBottom > contentHeight
}

Solution 14 - Ios

My solution is to add cells before tableview will decelerate on estimated offset. It's predictable on by velocity.

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)offset {
    
    NSLog(@"offset: %f", offset->y+scrollView.frame.size.height);
    NSLog(@"Scroll view content size: %f", scrollView.contentSize.height);
    
    if (offset->y+scrollView.frame.size.height > scrollView.contentSize.height - 300) {
        NSLog(@"Load new rows when reaches 300px before end of content");
        [[DataManager shared] fetchRecordsNextPage];
    }
}

Solution 15 - Ios

> Update for Swift 3

Neoneye's answer worked best for me in Objective C, this is the equivalent of the answer in Swift 3:

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    let offset: CGPoint = scrollView.contentOffset
    let bounds: CGRect = scrollView.bounds
    let size: CGSize = scrollView.contentSize
    let inset: UIEdgeInsets = scrollView.contentInset
    let y: CGFloat = offset.y + bounds.size.height - inset.bottom
    let h: CGFloat = size.height
//        print("offset: %f", offset.y)
//        print("content.height: %f", size.height)
//        print("bounds.height: %f", bounds.size.height)
//        print("inset.top: %f", inset.top)
//        print("inset.bottom: %f", inset.bottom)
//        print("position: %f of %f", y, h)

    let reloadDistance: CGFloat = 10

    if (y > h + reloadDistance) {
            print("load more rows")
    }
}

Solution 16 - Ios

I want perform some action on my any 1 full Tableviewcell.

So the code is link the :

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    NSArray* cells = self.tableView.visibleCells;
    NSIndexPath *indexPath = nil ;

    for (int aIntCount = 0; aIntCount < [cells count]; aIntCount++)
    {

        UITableViewCell *cell = [cells objectAtIndex:aIntCount];
CGRect cellRect = [self.tableView convertRect:cell.frame toView:self.tableView.superview];

        if (CGRectContainsRect(self.tableView.frame, cellRect))
        {
            indexPath = [self.tableView indexPathForCell:cell];

	//  remain logic
        }
     }
}

May this is help to some one.

Solution 17 - Ios

@neoneye's answer worked for me. Here is the Swift 4 version of it

    let offset = scrollView.contentOffset
    let bounds = scrollView.bounds
    let size = scrollView.contentSize
    let insets = scrollView.contentInset
    let y = offset.y + bounds.size.height - insets.bottom
    let h = size.height
    let reloadDistance = CGFloat(10)
    if y > h + reloadDistance {
        //load more rows
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSon NguyenView Question on Stackoverflow
Solution 1 - IosneoneyeView Answer on Stackoverflow
Solution 2 - IosEyeballView Answer on Stackoverflow
Solution 3 - Ios8suhasView Answer on Stackoverflow
Solution 4 - IosIftach OrrView Answer on Stackoverflow
Solution 5 - IosAjayView Answer on Stackoverflow
Solution 6 - IosWolfgang SchreursView Answer on Stackoverflow
Solution 7 - IosAnomieView Answer on Stackoverflow
Solution 8 - Iosuser1641587View Answer on Stackoverflow
Solution 9 - IosJay MayuView Answer on Stackoverflow
Solution 10 - Iosfootyapps27View Answer on Stackoverflow
Solution 11 - IosMorshed AlamView Answer on Stackoverflow
Solution 12 - IosShaik RiyazView Answer on Stackoverflow
Solution 13 - IossamwizeView Answer on Stackoverflow
Solution 14 - IosfirView Answer on Stackoverflow
Solution 15 - IosIbrahimView Answer on Stackoverflow
Solution 16 - IosMayuri R TalaviyaView Answer on Stackoverflow
Solution 17 - IosAnuran BarmanView Answer on Stackoverflow