Is there any way while the user is scrolling an uitableview to know when one of the many uitableviewcells is offscreen by 70% when reaching the top? Should i use willdisplaycell for this? Any help appreciated.
Implement scrollViewDidScroll...
get the frame of the row / cell you want to track
compare it to the scroll offset to see how much of it is visible
In this simple example, rowToTrack is an NSInteger, such as 2 for the 3rd row, sectionToTrack is an NSInteger, such as 0 for the 1st section:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// index path for row we want to track
NSIndexPath *p = [NSIndexPath indexPathForRow:rowToTrack inSection:sectionToTrack];
// get frame for that row
CGRect r = [self.tableView rectForRowAtIndexPath:p];
// get bottom of row frame
CGFloat t1 = CGRectGetMaxY(r);
// get scroll content offset
CGFloat t2 = scrollView.contentOffset.y + scrollView.adjustedContentInset.top;
// height of visible portion of row frame
CGFloat visibleHeight = t1 - t2;
// as a percentage between 0 and 1
CGFloat pct = MAX(0.0, MIN(1.0, visibleHeight / r.size.height));
NSLog(#"Row %ld is %0.2f percent visible", rowToTrack, pct * 100);
}
Is there a way to trigger an event, such as with an IBAction, when a user scrolls to the bottom of a UITableView? I would like to add more rows if this happens. How do I do this?
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.
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];
}
}
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.
NSInteger currentOffset = scrollView.contentOffset.y;
NSInteger maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
// Hit Bottom?
if ((currentOffset > 0) && (maximumOffset - currentOffset) <= 10) {
// Hit Bottom !!
}
It can be achieved in much simpler way I guess, you just need to determine the scrolling direction as in this case it is when the user is scrolling downwards.
First in your .h file declare a variable :
CGPoint pointNow;
In .m file, in scrollViewDidScroll method we need to implement this code:-
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y > pointNow.y) {
//Enter code here
}
}
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.
I'm not sure why you'd want to do this, but I imagine you could add some code to your cellForRowAtIndexPath method so that if indexPath.row == the last row, call the method to add more rows...
I'm trying to achieve next behavior:
I add few items in the beginning of UICollectionView
Items are added with proper animation, but I keep content offset on current center cell (it will be first cell before adding new items).
How I'm doing it now:
[self.collectionView performBatchUpdates:^{
CGPoint contentOffset = self.collectionView.contentOffset;
contentOffset.x += kMyCollectionViewCellWidth * firstIndex;
((MyCollectionViewLayout *)self.collectionView.collectionViewLayout).proposedContentOffset = contentOffset;
[self.collectionView insertItemsAtIndexPaths:indexesToAdd];
} completion:nil];
And in MyCollectionViewLayout.m:
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset {
if (self.proposedContentOffset.x != NSNotFound) {
proposedContentOffset = self.proposedContentOffset;
CGPoint zeroPoint = CGPointZero;
zeroPoint.x = NSNotFound;
self.proposedContentOffset = zeroPoint;
}
return proposedContentOffset;
}
Though, on slow devices I can see weird animation of adding this cells. New cells appears above old ones and moves left, when I want them appear in the left immediately or at least under old cells.
I have an UICollectionView in which each cell contains a PFObject. As there are potentially hundreds of these objects for each UICollectionView, I don't want to query all the objects at once, and instead only call a limited amount, and then automatically call for more as the user scroll towards the end (somewhat like endless scrolling that many web apps use).
Would PFQuery support these type of calls, and if so how would I be able to call continuously and automatically?
Thanks!
Perhaps something like this to get you on the right track:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
float scrollViewHeight = scrollView.frame.size.height;
float scrollContentSizeHeight = scrollView.contentSize.height;
else if (scrollView.contentOffset.y <= 0) {
// then we are at the top
}
else if (scrollView.contentOffset.y + scrollViewHeight >= scrollContentSizeHeight) {
// then we are at the bottom - query new results
}
}
I don't think you'd have to add anything for it to call as long as your controller is already your collectionView's delegate.
I have a UITableview that I'm trying to append data to when the user scrolls near the bottom. I've written this method to detect the scroll and it functions correctly but looks bad.
- (void)scrollViewDidScroll:(UIScrollView *)scroll {
NSInteger currentOffset = scroll.contentOffset.y;
NSInteger maximumOffset = scroll.contentSize.height - scroll.frame.size.height;
if (maximumOffset - currentOffset <= 5) {
[self loaddata:[NSString stringWithFormat:#"%d", celltitle.count]];
}
}
loaddata has a number passed to it which is used to limit the returning cells from the database correctly. i.e. LIMIT x, (x+20)
Like I said the data loads but each time it goes to load it the scrolling pauses and then resumes. The NSURLConnection is synchronous. Could that be a problem?