我有一个典型的UICollectionView,它以垂直方式使用UICollectionViewFlowLayout。我正在使用带有分页的rest 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,看到加载资产的第一页。如果我向下滚动,我将看到页脚视图(包含一个微调器),但代码将在行的异常断点处中断:
[weakSelf.collectionView insertItemsAtIndexPaths:indexPaths];
断言失败 - [UICollectionViewData layoutAttributesForSupplementaryElementOfKind:atIndexPath:],/ SourceCache / UIKit / UIKit3185.20 / UICollectionViewData.m:829
然后,如果我继续崩溃,则会出现错误:
2014-06-11 16:39:58.335 Radius-iOS [4901:525006] *由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'没有UICollectionViewLayoutAttributes实例用于-layoutAttributesForSupplementaryElementOfKind:路径中的UICollectionElementKindSectionFooter {length = 2,路径= 0 - 0}' * 首先抛出调用堆栈:
这令我感到困惑。 layoutAttributesForSupplementaryElementOfKind听起来像是与布局类有关,但我没有使用自定义流布局而是提供默认布局。听起来Apple的代码很疯狂,但我觉得我正在使用一切。
现在,如果我移动电话:
[self loadNextPageOfAssets];
从补充单元格出列到UICollectionViewCell deque,并将所有页脚视图一起删除,然后插入效果很好。
现在我正在调用reloadData而不是insert,但这是UGLY。
我是否忽略了有关页脚的内容?
答案 0 :(得分:10)
VaporwareWolf提供的答案有点像黑客。通过返回一个小尺寸而不是零尺寸,补充视图将始终存在但尺寸太小而无法看到。这就是它解决 NSInternalInconsistencyException
的原因但是,有一个真正的解决方案。
将数据添加到数据源后
在调用insertItemsAtIndexPaths
之前,只需使集合视图上的布局无效,以使其了解更改。
目标C
[self.collectionView.collectionViewLayout invalidateLayout]
夫特
collectionView.collectionViewLayout.invalidateLayout()
答案 1 :(得分:9)
事实证明我实际上遇到了布局问题(如错误说明所示)
- (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)。这是唯一必要的改变。它现在按预期运行。
答案 2 :(得分:0)
俄语中有一篇关于UICollectionView中的错误的文章:http://habrahabr.ru/post/211144/。
以下是该文章中可能解决您问题的几种方法:
@try {
[self.collectionView insertItemsAtIndexPaths:indexPaths];
}
@catch (NSException *exception) {}
或
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadData];
} completion:nil];
答案 3 :(得分:0)
您应该实现两种(页眉和页脚)方法。即使你只想要一个。看看我的代码
-(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;
}