在 UICollectionView 底部加载其他单元格

Posted

技术标签:

【中文标题】在 UICollectionView 底部加载其他单元格【英文标题】:Loading additional cells at the bottom of UICollectionView 【发布时间】:2013-06-18 23:47:53 【问题描述】:

当用户滚动到UICollectionView 的底部时,我试图自动获取并加载下一页单元格。

我可以通过在UICollectoinView 页脚中添加UIButton 来做到这一点。当用户滚动到页脚并触摸按钮时,新单元格被正确添加。可以再次触摸页脚中的UIButton 以添加更多页面。

我尝试将其自动化,因此当用户滚动到底部时,会自动调用添加新单元格的正确方法:

- (UICollectionReuseableView *)collectionView: (UICollectionView *)collectionView viewForSupplementaryElementOfKind: (NSString *)kind atIndexPath: (NSIndexPath *) indexPath


    // code for headerView
    // ...

    // code for footerView
    MySupplementalFooter *footerView = nil;
    if ( [kind isEqual:UICollectionElementKindSectionFooter] )
    
        footerView = [self.collectionView dequeueReuseableSupplemntaryViewOfKind:kind withReuseIdentifier:@"FooterId" forIndexPath:indexPath];
        if (LoadMoreIsEnabled) 
        
            footerView.loadMoreFooterButton.setHidden:NO];
            [self loadMoreFooterButtonAction]; // calls the method to add cells to the dictionary for cv 
         else 
        
             footerView.loadMoreFooterButton setHidden:YES];
        

        return footerView;
    

loadMoreFooterButtonAction 方法被调用,但整个 UICollectionView 被删除。刷新 UICollectionView 并不会将其恢复。

【问题讨论】:

UICollectionView blanks out OMG,这就是我的情况,我尝试了willDisplayCell 的常用方法,但集合视图重置并变为空白(wtf)。最后使用scrollViewDidScroll实现。 【参考方案1】:

ios8中有一个UICollectionViewDelegate方法willDisplayCell

func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) 
    if indexPath.item == (data.count-1) 
        loadData()
    

【讨论】:

我想为此添加一些行为知识。如果用户上下滚动,即使在本节末尾,您也可能会遇到多次调用 loadData() 的情况。我添加了一个 bool 来控制何时可以再次调用 loadData()。但是, indexPath.item 正是要使用的动态引用。好电话***.com/users/2604669/nick-wargnier UICollectionView blanks out 有人遇到过这种情况吗?我尝试了通常的willDisplayCell,但集合视图重置并变为空白(wtf)。 @SoftDesigner 我也遇到了同样的问题,原来是因为主线程上没有调用 reloadData。我敢肯定不是为时已晚,但对于未来的其他人来说! @SoftDesigner ,我面临同样的问题。您找到解决方案了吗?【参考方案2】:

在表格视图中,您应该在 willDisplayCell() 方法中加载更多数据。对于集合,没有这样的对应物。但是,你可以这样做。希望,它会有所帮助。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
    // Other code here ...

    if (indexPath.item == [self.photos count] - 1) 
        [self loadPhotos];
    

    return cell;


- (void)loadPhotos 
    [self showLoadingIndicator];
    self.operation = [client HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) 
        [self hideLoadingIndicator];

        // Get data
        NSArray *photosData = responseObject[@"data"];
        NSInteger numberOfResults = [photosData count];
        NSInteger totalCount = [self.photos count];

        if (numberOfResults > 0) 
            NSMutableArray *indexPaths = [NSMutableArray new];

            for (NSInteger i = 0; i < numberOfResults; i++) 
                Photo *photo = [Photo new];
                photo._id = [photoData[@"id"] integerValue];
                photo.url = photoData[@"url"];

                [self.photos addObject:photo];
                [indexPaths addObject:[NSIndexPath indexPathForRow:totalCount + i
                                                     inSection:0]];
            

            [self.collectionView performBatchUpdates:^
                [self.collectionView insertItemsAtIndexPaths:indexPaths];
             completion:nil];
                
     failure:^(AFHTTPRequestOperation *operation, NSError *error) 
        [self hideLoadingIndicator];
        // Handle error here
    ];

   [self.operation start];

【讨论】:

现在 UICollectionView 在 iOS8 中有 willDisplayCell 委托。 我们应该在loadMoredata方法中实现什么? @Bhumica 我更新了我的答案。这是 AFNetworking 的一个示例。 @vampirewalk 但是,很多应用程序仍然支持 iOS 7。 我也在做同样的事情。但是,问题是如果我插入单元格,以前的单元格就会消失,然后加载,collectionView 会自行滚动到顶部。 @Sukhrob 我正在使用 Xcode for iOS 应用程序,目标是 iOS 10 及更高版本。【参考方案3】:

我知道这是一个老问题,但我会为未来的答案寻求者提供解决方案。通常当我在 UITableView 上进行无限滚动时,我会检查 tableView 的滚动视图的边界是否与 tableFooterView 的矩形相交。在 UICollectionViews 中获取页脚视图有点复杂,所以我在 collectionView 的末尾创建一个矩形,看看它是否与 scrollView 边界相交,如果是,我会加载更多项目。我还检查了表格中是否至少有一些东西,所以我不会在表格实例化时尝试加载更多内容。

注意:在这种情况下,您的 more 方法将更新您的 collectionView 数据源,并附加新项目。您的 numberOfItems/sections 方法应该反映新的计数。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

    if (CGRectIntersectsRect(scrollView.bounds, CGRectMake(0, self.collectionView.contentSize.height, CGRectGetWidth(self.view.frame), 40)) && self.collectionView.contentSize.height > 0)
    
        [self more];
    

【讨论】:

在我的收藏视图中非常适合我 这会调用 [self more] 很多次,而不是像预期的那样只调用一次。 正确。在 more 中,您需要添加状态以指示您是否正在加载更多。【参考方案4】:

您也可以使用collectionView(_:prefetchItemsAt:) 教程1和2。

【讨论】:

【参考方案5】:

我假设您正在尝试从桌面网页执行“无限滚动”之类的操作,当用户到达页面底部时,您会在其中加载更多内容。在 iOS 上,这不是一个非常常用的设计。通常,开发人员将使用绝对条目总数初始化他们的 UITableView 或 UICollectionView。如果他们需要通过网络流式传输数据,他们会根据需要异步加载数据(当单元格或视图出现在屏幕上时),直到内容加载,他们才会显示某种临时内容,例如带有微调器的空白视图。

也就是说,如果您想以更像桌面 Web 应用程序的方式进行无限滚动,您应该实现 UIScrollViewDelegate 协议(或 UICollectionViewDelegate,它是一个超集)并监听 scrollViewDidScroll: 回调。在该回调中,遍历 UICollectionView 的 indexPathsForVisibleItems 并检查是否有任何索引路径映射到集合中的“最后一个”项目,这表明用户已滚动到最后。此时,调用您的逻辑以加载更多内容。

【讨论】:

“通常,开发人员将使用绝对条目总数初始化他们的 UITableView 或 UICollectionView。” [需要引用]【参考方案6】:

我在将@sukhrob 的答案转换为我的项目的 swift 时遇到了困难,所以这里是他在 Swift 3 中的代码,以便于复制和粘贴。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        // Other code here ...
        if indexPath.item == photos.count() - 1 
            loadPhotos()
        
        return cell
    

    func loadPhotos() 
        showLoadingIndicator()
        operation = client.httpRequestOperation(with: request, success: (_ operation: AFHTTPRequestOperation, _ responseObject: Any) -> Void in
            self.hideLoadingIndicator()
                // Get data
            let photosData: [Any] = responseObject["data"]
            let numberOfResults: Int = photosData.count
            let totalCount: Int = photos.count()
            if numberOfResults > 0 
                var indexPaths = [Any]()
                var i = 0
                while i < numberOfResults 
                    let photo = Photo()
                    photo.id = CInt(photoData["id"])
                    photo.url = photoData["url"]
                    photos.append(photo)
                    indexPaths.append(IndexPath(row: totalCount + i, section: 0))
                    i
                
                i += 1

        collectionView?.performBatchUpdates(() -> Void in
                    collectionView?.insertItems(at: indexPaths as? [IndexPath] ?? [IndexPath]())
                )  _ in 
            
        , failure: (_ operation: AFHTTPRequestOperation, _ error: Error?) -> Void in
            self.hideLoadingIndicator()
            // Handle error here
        )
        operation.start()

【讨论】:

以上是关于在 UICollectionView 底部加载其他单元格的主要内容,如果未能解决你的问题,请参考以下文章

uicollectionview 在底部滚动加载更多数据。 iOS 斯威夫特

如何在 UICollectionView 中加载更多数据而不重新加载所有数据

在 UICollectionView 的底部添加额外的单元格

UIView 在滚动时从 UICollectionView 的底部分离

UICollectionView 重新加载数据导致图形故障

在 iOS 的 UICollectionview 底部添加按钮