UICollectionView + AFNetworking + AutoScroll/Pagination?

Posted

技术标签:

【中文标题】UICollectionView + AFNetworking + AutoScroll/Pagination?【英文标题】:UICollectionView + AFNetworking + AutoScroll/Pagination? 【发布时间】:2014-07-14 23:56:02 【问题描述】:

我使用UICollectionView + AFNetworking 2 从网络服务异步加载图像。它工作得很好。但是,如何实现自动滚动(当用户到达或接近页面底部时,调用 API 以获取更多单元格)。

我看过很多示例,但似乎没有最佳做法。例如,一个教程建议scrollViewDidScroll,但每次滚动视图时都会调用它。这是正确的实现方式吗?

PS。我正在用 Swift 编写代码。

这是我的单元格创建代码:

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

【问题讨论】:

我不久前发布了这个。它不是 Swift,但也许这就是您想要实现的目标。 ***.com/questions/5137943/… 感谢眼球。我能够检测到用户何时滚动到屏幕底部,但每次到达屏幕底部时都会检测到它,这可能会在 Web 服务返回任何结果之前发生多次,从而再次调用 Web 服务。我对更全面的解决方案感兴趣,包括如何跟踪应用程序中的分页偏移量、何时调用 afnetworking、如何指示屏幕正在重新加载。 我会在-scrollViewDidScroll: 中进行。即使在滚动时在每一帧都调用它,性能也不应该成为问题。只需检查您是否接近底部(将偏移量与内容高度进行比较)并在需要时加载新图像。 【参考方案1】:

您可以在scrollViewDidScroll 委托方法或collectionView:cellForItemAtIndexPath: 中执行此操作(在这里您可以检测到最后一个单元格正在加载)。您需要做的是为AFNetworking 调用创建一个包装器,以防止它多次加载数据(某种标志表明它已经在加载)。

之后,您可以在底部插入带有某种活动指示器的其他单元格,并在 AFNetworking 调用完成后将其删除。

【讨论】:

感谢 blazejmar,有趣的建议。您是否在 ViewController 中保留一个变量来跟踪分页的偏移量?我将不得不研究如何使用 UICollectionView 插入看起来不错的单元格,而不是 UITableView。让我试试这个方法。 这真的取决于你的 API 是如何工作的。如果您必须传递偏移量和页面大小,则需要将其存储在某个地方。 VC似乎是个好地方。如果您的 API 使用您拥有的最后一个对象的 id,那么您不需要创建任何额外的变量来存储它。 reloadData调用collectionView函数刷新视图。如何将刷新限制为仅限新内容,而不是所有内容? 你在使用 CoreData 吗?如果是,那么您可以使用 NSFetchedResultsController 并使用其委托方法回调来收集所有插入/删除/更新的对象。如果不是,您必须跟踪已更改的对象。无论哪种方式,最终您都可以调用 performBatchUpdates: - insertItemsAtIndexPaths: – moveItemAtIndexPath:toIndexPath: – deleteItemsAtIndexPaths: inside。【参考方案2】:

您应该使用 willEndDragging UIScrollview 委托方法来确定滚动视图将停止滚动的位置。 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset

与其他方法相比,这具有几个优势:

    didScroll 将在每次滚动视图滚动时被调用,即使是部分滚动,甚至当您从代码中触发它时也是如此。我已经看到 didScroll 即使在边界发生变化时也会被调用,例如当方向发生变化时,尤其是在 iPad 上。它只是被调用太频繁了! 如果滚动视图突然停止,didEndDecelerating 可能不会被调用 - 例如当用户在滚动视图变慢时按住并保持滚动视图 willEndDragging 只会在用户滚动您的滚动视图时调用,而不是通过代码/布局更改。

在 willEndDragging 中,使用 target 内容偏移量来确定是否需要加载更多结果。一旦您的 API 完成数据获取,只需在集合视图上调用 reloadData 即可显示新结果。请注意,目标 contentOffset 是一个指针,因此您必须使用 targetContentOffset->y 来获取目标 y 位置。

执行此操作的实际代码将取决于实现,因此我没有放入任何示例,但它应该足够简单,可以编写代码。

【讨论】:

【参考方案3】:

是的,使用scrollViewDidScroll 来检查你是否在底部,而不是做任何你需要的工作(放置加载器、加载数据等等)。

您可以使用现成的组件 SVInfiniteScrolling(它是 SVPullToRefresh 的一部分)。或者看看它的implementation 以获得灵感。

编码愉快!

【讨论】:

【参考方案4】:

我在我的项目中使用此代码。我是用 Obj-C 编写的,但对将其转换为 Swift 知之甚少。因此,如果您可以转换,您可以检测自己是否像这样到达页面末尾;

- (BOOL)detectEndofScroll

    BOOL scrollResult = NO;
    CGPoint offset = _collectionView.contentOffset;
    CGRect bounds = _collectionView.bounds;
    CGSize size = _collectionView.contentSize;
    UIEdgeInsets inset = _collectionView.contentInset;
    float yAxis = offset.y + bounds.size.height - inset.bottom;
    float h = size.height;
    if(yAxis+14 > h)
    
        scrollResult = YES;
    
    else
    
        scrollResult = NO;
    
    return scrollResult;


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

    if ([self detectEndofScroll])
    
        // load more data
    

【讨论】:

不错的尝试和方法。

以上是关于UICollectionView + AFNetworking + AutoScroll/Pagination?的主要内容,如果未能解决你的问题,请参考以下文章

折叠UICollectionView

-[UICollectionView _endItemAnimations] 中的 UICollectionView 断言失败

如何滚动另一个 UICollectionView 下方的 UICollectionView?

UICollectionView 单元内部已加载,但 UICollectionView 未显示

UICollectionView 断言失败 -[UICollectionView _updateWithItems:tentativelyForReordering:]

UITableviewCell 中的 UICollectionView。添加约束后,UICollectionView 不显示