Add rows to UITableView when scrolled to bottom
Solution 1
Simply listen to the scrollViewDidScroll:
delegate method, compare the content offset with the current possible offset and if lower then some threshold call your method to update the tableview. Don't forget to call [tableView reloadData]
to make sure it reload the newly added data.
EDIT: Put together abstract code, not sure if it works, but should.
- (void)scrollViewDidScroll: (UIScrollView *)scroll {
// UITableView only moves in one direction, y axis
CGFloat currentOffset = scroll.contentOffset.y;
CGFloat maximumOffset = scroll.contentSize.height - scroll.frame.size.height;
// Change 10.0 to adjust the distance from bottom
if (maximumOffset - currentOffset <= 10.0) {
[self methodThatAddsDataAndReloadsTableView];
}
}
Solution 2
Unless it´s a little late, but i think i found a better solution:
instead of
- (void)scrollViewDidScroll: (UIScrollView)scroll
i used
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
This is much more convenient, cause the event is only triggered once. I used this code in my application to load more rows in my tableview at the bottom (maybe you recognize this type of reloading from the facebook application - only difference that they are updating at the top).
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSInteger currentOffset = scrollView.contentOffset.y;
NSInteger maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
if (maximumOffset - currentOffset <= -40) {
NSLog(@"reload");
}
}
Hope anyone will help this.
Solution 3
I use this snippet. in tableView:willDisplayCell:forRowAtIndexPath:
I check, if the cell with the last index path is about to be diplayed.
For a tableView with one section:
[indexPath isEqual:[NSIndexPath indexPathForRow:[self tableView:self.tableView numberOfRowsInSection:0]-1 inSection:0]
with more sections:
[indexPath isEqual:[NSIndexPath indexPathForRow:[self tableView:self.tableView numberOfRowsInSection:0]-1 inSection:[self numberOfSectionsInTableView:self.tableView]-1]
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(!_noMoreDataAvailable)
{
if ([indexPath isEqual:[NSIndexPath indexPathForRow:[self tableView:self.tableView numberOfRowsInSection:0]-1 inSection:0]])
{
[self.dataSourceController fetchNewData];
}
}
}
after fetching the dataSourceController will inform the tableView delegate and this will reload the data.
Solution 4
Swift
Here is the Swift version of @user944351's answer:
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height
if maximumOffset - currentOffset <= -40 {
print("reload")
}
}
Just add this method to your UITableView
delegate class. I found -40
too large but you can adjust it according to your needs.
More info
- See my fuller answer that has an example of method to reload data using limits and offsets for the database.
Solution 5
NSInteger currentOffset = scrollView.contentOffset.y;
NSInteger maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
// Hit Bottom?
if ((currentOffset > 0) && (maximumOffset - currentOffset) <= 10) {
// Hit Bottom !!
}
Comments
-
aherlambang about 4 years
Is there a way to trigger an event, such as with an
IBAction
, when a user scrolls to the bottom of aUITableView
? I would like to add more rows if this happens. How do I do this? -
aherlambang about 13 yearsbecause I would like to call a REST web service to add more rows as there are more entries that can be seen by the user, instead of having a "load more posts" kind of thing, why not do it automatically
-
Henri Normak about 13 yearsDon't have a project atm to quickly show something in. I presume your viewController is the delegate of the tableView. If so, just add scrollViewDidScroll: to the viewController and use that as the place to trigger the update method. Comparing the contentOffset.y with maximum (contenSize.y - tableView.frame.size.height) should be quite straightforward.
-
Henri Normak about 13 yearsThe key is to realize that UITableView is a subclass of UIScrollView and it passes on the delegate methods as well.
-
aherlambang about 13 yearsand will this be triggered once the scrolling is stopped or will it also execute while scrolling?
-
Henri Normak about 13 yearsI believe this is triggered every single time the contentOffset changes, meaning if you scroll, this will get triggered a lot. Which reminds me, if you are doing a request from the web, you should probably disable this system for the time being when the request is ongoing and reenable once content has been added. Just add a boolean somewhere isUpdating and check that along with the offset difference.
-
aherlambang about 13 yearswhy is it also firing the method [self methodThatAddsDataAndReloadsTableView];
-
Henri Normak about 13 yearsWhat do you mean by that? I added that line just so you know where to put all your updating stuff into, you started the question with a desire to trigger an event when the scrollView was at the bottom, that event should go instead of the [self methodThatAddsDataAndReloadsTableView]; line.
-
Ben over 10 yearsThis is what I needed to only make a single call to my server.
- (void)scrollViewDidScroll:
is triggered to many times to make a call to your server. Unless you do as @Henri Normak suggested above in his comments and add a check for updating. This is much simpler. Thanks @user944351 -
Rob over 10 yearsBrilliant answer, much prefer this compared scrollViewDidScroll option - thanks vikingosegundo!
-
Sjoerd Perfors about 10 yearsIf you use loading or error cells, be sure to have a small check like: if(indexPath.row > 5) or simple set the boolean noMoreDataAvailble to false.
-
User almost 10 yearsI tested this but it only works when the drag starts when the table view is already near to the bottom. If it's a long scroll, the if condition is not met even if it ends exactly at the bottom.
-
User almost 10 yearsMakes sense since the method is called "end dragging" so I think is called with the offset when the user ends the drag gesture. But the list can continue scrolling. And it should load automatically when it reaches the bottom, so it looks like
scrollViewDidScroll
is correct. -
Robert J. Clegg about 9 yearsNot great if you want to load the data a little way before the user gets to the last cell. I find it 'flows' better when you load it a few cells before
-
vikingosegundo about 9 years@Tander, you should be able to change that to an earlier indexPath.
-
iOS Lifee over 6 yearsSame code in swift 3 let currentOffset: Int = Int(scrollView.contentOffset.y) let maximumOffset = Int(scrollView.contentSize.height - scrollView.frame.size.height) if maximumOffset - currentOffset <= -40 { print("got") }
-
daniel over 5 yearsIs this a callback function that is called by the system?