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 _endItemAnimations] 中的 UICollectionView 断言失败
如何滚动另一个 UICollectionView 下方的 UICollectionView?
UICollectionView 单元内部已加载,但 UICollectionView 未显示
UICollectionView 断言失败 -[UICollectionView _updateWithItems:tentativelyForReordering:]
UITableviewCell 中的 UICollectionView。添加约束后,UICollectionView 不显示