插入到包含页脚的UICollectionView部分的问题

我有一个典型的UICollectionView,它以垂直方式使用UICollectionViewFlowLayout。 我正在使用分页API来填充集合视图。 为了触发下一个页面的下载,我在使用委托时要求页脚布局:

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{ RDLoadMoreReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"RDLoadMoreReusableView" forIndexPath:indexPath]; view.delegate = self; [view start]; [self loadNextPageOfAssets]; return view; } 

这里是我的loadNextPageOfAssets背后的代码:

 -(void)loadNextPageOfAssets{ __weak RDRadiusGridViewController *weakSelf = self; // Increment page and request assets. They are added to cluster.assets before the completion block is called. self.cluster.pagination.page++; [self.cluster requestAssetsWithCompletionBlock:^(NSArray *assets) { SM_LOG_DEBUG(@"page.total: %ld assets.count: %ld", self.cluster.pagination.totalCount, (long)assets.count); NSMutableArray *indexPaths = [[NSMutableArray alloc]initWithCapacity:assets.count]; for(NSUInteger index = 0; index < assets.count; index++){ NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.cluster.assets.count - assets.count + index inSection:0]; SM_LOG_DEBUG(@"Inserting indexPath: %ld:%ld", (long)indexPath.item, (long)indexPath.section); [indexPaths addObject:indexPath]; } [weakSelf.collectionView performBatchUpdates:^{ [weakSelf.collectionView insertItemsAtIndexPaths:indexPaths]; } completion:^(BOOL finished) { }]; // [weakSelf.collectionView reloadData]; }]; } 

当我运行我可以去我的ViewController,并看到加载资产的第一页。 如果向下滚动,我会看到页脚视图(其中包含一个微调框),但是代码会在exception中断点处断开:

 [weakSelf.collectionView insertItemsAtIndexPaths:indexPaths]; 

断言失败 – [UICollectionViewData layoutAttributesForSupplementaryElementOfKind:atIndexPath:],/ SourceCache /UIKit/UIKit-3185.20/UICollectionViewData.m:829


然后,如果我继续它与错误崩溃:

2014-06-11 16:39:58.335 Radius-iOS [4901:525006] *由于未捕获exception'NSInternalInconsistencyException',原因:'no UICollectionViewLayoutAttributes instance for -layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionFooter at path {length = 2,path = 0 – 0}'*第一次抛出调用堆栈:


这令我感到困惑。 layoutAttributesForSupplementaryElementOfKind听起来像是与布局类有关的东西,但我没有使用自定义stream布局,而是使用默认提供的布局。 这听起来像苹果的代码是疯了,但我觉得我使用正确的一切。

现在,如果我移动电话:

 [self loadNextPageOfAssets]; 

从补充单元出列到UICollectionViewCell deque,并一起去除页脚视图,然后插入工作很好。

现在我打电话reloadData而不是插入,但这是丑陋的。

我可以忽略一些关于页脚的东西吗?

VaporwareWolf提供的答案有点破解。 通过返回小尺寸而不是零尺寸,补充视图将始终存在,但尺寸太小,看不到。 所以这就是为什么它修复NSInternalInconsistencyException

但是,有一个真正的解决scheme

将数据添加到数据源之后, 调用insertItemsAtIndexPaths 之前 ,只需使collectionview中的布局无效,以使其知道更改。

Objective-C的

 [self.collectionView.collectionViewLayout invalidateLayout] 

迅速

 collectionView.collectionViewLayout.invalidateLayout() 

事实certificate,我实际上遇到了布局问题(如错误描述所示)

 - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section{ if(<myDecision>){ return CGSizeZero; } else { return CGSizeMake(320, 50); } } 

CGSizeZero是导致崩溃的原因。 而是使用CGSizeMake(0.001,0.001)。 这是唯一必要的改变。 它现在按预期运行。

在俄罗斯有一个关于UICollectionView中的bug的巨大文章: http ://habrahabr.ru/post/211144/。

这篇文章中有几个方法可以解决你的问题:

 @try { [self.collectionView insertItemsAtIndexPaths:indexPaths]; } @catch (NSException *exception) {} 

要么

 [self.collectionView performBatchUpdates:^{ [self.collectionView reloadData]; } completion:nil]; 

你应该实现(Header和Footer)方法。 即使你只想要一个。 看看我的代码

 -(UICollectionReusableView *) collectionView:(UICollectionView *) collectionView viewForSupplementaryElementOfKind:(NSString *) kind atIndexPath:(NSIndexPath *) indexPath { UICollectionReusableView *header = [[UICollectionReusableView alloc] init]; if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionViewHeader" forIndexPath:indexPath]; } else { header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"CollectionViewHeader" forIndexPath:indexPath]; } return header; } -(CGSize) collectionView:(UICollectionView *) collectionView layout:(UICollectionViewLayout *) collectionViewLayout referenceSizeForHeaderInSection:(NSInteger) section { return CGSizeMake(self.view.frame.size.width, 100); } -(CGSize) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section { return CGSizeZero; }