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

标签: ios objective-c swift uicollectionview afnetworking


【解决方案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

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

  1. didScroll 将在每次滚动视图滚动时被调用,即使是部分滚动,甚至当您从代码中触发它时也是如此。我已经看到 didScroll 即使在边界发生变化时也会被调用,例如当方向发生变化时,尤其是在 iPad 上。它只是被调用太频繁了!
  2. 如果滚动视图突然停止,didEndDecelerating 可能不会被调用 - 例如当用户在滚动视图变慢时按住并保持滚动视图
  3. 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
          }
      }
      

      【讨论】:

      • 不错的尝试和方法。
      猜你喜欢
      • 2015-02-22
      • 1970-01-01
      • 2014-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-31
      • 2013-05-25
      相关资源
      最近更新 更多