Swift 4 如何检测 UICollectionView 滚动结束

11

我的应用程序中有一个HorizontalUICollectionView,我想在用户拖动到左侧的末尾(或接近末尾)时加载更多数据。

我正在使用Swift 4。我找到了一些Swift 3的解决方案,但它们对我无效。

我的当前代码如下:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return self.videoViewModel.images.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
    cell.imgImage.image = self.videoViewModel.images[indexPath.row]

    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    updateVideo(data: self.videoViewModel.relatedVideos[indexPath.row])
}

有多少个可见单元格? - McDonal_11
从 API 加载数据? - iVarun
首先我加载10,然后每当滚动条到达末尾某一点时,我需要再次添加10。@McDonal_11 - M1X
是的,我正在从API加载数据 @ivarun - M1X
5个回答

21

您可以使用集合视图的cellForItem或willDisplayItem方法。检查最后一个单元格是否正在显示,并加载您的数据。例如:

Swift:

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
     if (indexPath.row == dataSource.count - 1 ) { //it's your last cell
       //Load more data & reload your collection view
     }
}

Objective-C:

- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == dataSource.count - 1 ) { //it's your last cell
       //Load more data & reload your collection view

    }
}

如果这对你没有帮助,请告诉我。 - Fayza Nawaz
1
是的,完全正确。但请确保适当处理边际情况 :) - Fayza Nawaz
因为单元格的项被提前调用,甚至在显示单元格之前就被调用了。例如,如果屏幕上显示了单元格#2、3、4、5,则即使对于单元格#6和可能的7,也会调用cellForItem以优化事物。希望这有意义。 - Fayza Nawaz
1
当然,我会解决它,放置一些布尔值或其他东西。谢谢。 - M1X
1
如果你能再等一秒钟的话 :p - M1X
显示剩余4条评论

10

实现UIScrollViewDelegatescrollViewDidScroll方法:

var isLoading: Bool = false

 func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let contentOffsetX = scrollView.contentOffset.x
    if contentOffsetX >= (scrollView.contentSize.width - scrollView.bounds.width) - 20 /* Needed offset */ {
        guard !self.isLoading else { return }
        self.isLoading = true
        // load more data
        // than set self.isLoading to false when new data is loaded
    }
}

1
我将这个方法放在了我的ViewController上,同时我也实现了UIScrollViewDelegate,但是没有任何反应。你可以在https://gitlab.com/rexhin/ios-kida.git检查我的代码。 - M1X
现在它能够触发,但如果我到达结尾,它会多次触发,比如10或20次。 - M1X
1
更新了答案。 - Ilya Kharabet
还不好。一开始它会触发大约20次,然后当我到达结尾时又会多次触发。 - M1X
我不能这样做,因为我正在使用另一个文件中的服务,而不是ViewController。我是这样做的。`func related(videoName: String) { videoViewModel.related(videoName: videoName) { (result: VideoViewModel.Related) in switch result { case .failure(let error): print(error) case .success( _): self.collectionView.reloadData() self.isLoading = false } } } `这是我调用加载数据的函数。 - M1X
显示剩余6条评论

1

拿一个bool变量和一个整数变量来表示页面编号,就像这样:

var isDataLoading = false
var pageCount:Int = 1 // Pass this page number in your api

在 cellForItemAt 方法中添加以下代码:
if !isDataLoading && indexPath.row == videoViewModel.count - 1 {
            isDataLoading = true
            pageCount += 1
// add you api call code here with pageCount
        }

一旦您从api获取到数据,请将isDataLoading的布尔值设置为false,如下所示:
self.isDataLoading = false

谢谢,但我更感兴趣的是检测滚动的结束。 - M1X

0

这是一个简单的登录,将会跳转到最后一个索引...!!!

func ScrollEnd() {
          let lastSectionIndex = (self.collectionView?.numberOfSections)! - 1
         let lastItemIndex = (self.collectionView.numberOfItems(inSection: lastSectionIndex)) - 1
           let index =  IndexPath(item: lastItemIndex, section: lastSectionIndex)
           if messages.count != 0{
               self.collectionView!.scrollToItem(at: index, at: UICollectionView.ScrollPosition.bottom, animated: false)
           }    }

0

将这段代码添加到你的 collectionView 的 willDisplayCell 代理方法中

if (indexPath.row == dataSource.count - 1 ) {
 //it's your last cell

//Load more data & reload your collection view
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接