Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView + AFNetworking + AutoScroll/Pagination?

I use UICollectionView + AFNetworking 2 for loading images asynchronously from a webservice. It's working great. However, how do I implement automatic scrolling (when user reaches bottom of page, or close to it, the API is called to fetch more cells).

I've seen lots of examples but there doesn't seem to be a best practice. For example, one tutorial suggested scrollViewDidScroll, but that's called every time the view is scrolled. Is that the correct implementation?

PS. I'm coding in Swift.

Here's my cell creation code:

func collectionView(collectionView: UICollectionView!, cellForItemAtIndexPath indexPath: NSIndexPath!) -> UICollectionViewCell! {

    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier, forIndexPath: indexPath) as UICollectionViewCell

    let offer = self.offers[indexPath.row]
    var cellImageView = cell.viewWithTag(100) as UIImageView
    let requestURL = NSURLRequest(URL: offer.largeImageURL)
    cellImageView.setImageWithURLRequest(
        requestURL,
        placeholderImage:placeholderImage,
        success: {
            (request:NSURLRequest!, response:NSHTTPURLResponse!, image:UIImage!) in
            cellImageView.image = image
        },
        failure: {
            (request:NSURLRequest!, response:NSHTTPURLResponse!, error:NSError!) in
            NSLog("GET Image Error: " + error.localizedDescription)
        }
    )
    return cell
}
like image 555
netwire Avatar asked Jul 14 '14 23:07

netwire


2 Answers

You could do it in a scrollViewDidScroll delegate method or collectionView:cellForItemAtIndexPath: (here you could detect that last cell is loading). What you would need to do is to create a wrapper for AFNetworking call to prevent it from loading the data few times (some kind of flag that indicates that it's already loading).

After that you could insert additional cell with some kind of activity indicator at the bottom and remove it after AFNetworking call is finished.

like image 71
blazejmar Avatar answered Nov 15 '22 04:11

blazejmar


You should use the willEndDragging UIScrollview delegate method to determine where the scrollview will stop scrolling. - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset

This has several advantages over the other methods:

  1. didScroll will be called for every time the scrollview scrolls, even fractionally, and even when you trigger it from code. I've seen didScroll get called even with a bounds change, like when the orientation changes, especially on iPad. It just gets called too often!
  2. didEndDecelerating may not get called if the scrollview comes to a sudden stop - like when the user presses and hold the scrollview while it's slowing
  3. willEndDragging will only be called when the user scrolls your scroll view, not by code / layout changes.

In the willEndDragging, use the target content offset to determine if you need to load more results. Once your API has finished fetching data, simply call reloadData on the collection view and the new results will be shown. Note that the target contentOffset is a pointer, so you'll have to use targetContentOffset->y to get the target y position.

The actual code to do this will be implementation dependent so I'm not putting in any sample, but it should be simple enough to code up.

like image 20
Dhiraj Gupta Avatar answered Nov 15 '22 06:11

Dhiraj Gupta