我有一个UICollectionView,其内容由NSFetchedResultsController提供。每当更新核心数据时,都会调用一个调用以通过 reloadItemsAtIndexPaths: 方法更新集合视图中已更改的项。
经过大量的测试,我确定上述过程工作正常。我对核心数据进行更新,最终调用数据源方法"cellForItemAtIndexPath",并按预期更新单元格。 但是,我也实现了数据源方法"viewForSupplementaryElementOfKind",以显示一些单元格标题(也基于对核心数据的更改),这无法正常工作。
出于某种原因,似乎在核心数据更改后调用"reloadItemsAtIndexPaths"时,"viewForSupplementaryElementOfKind"不会被调用,我无法弄清楚为什么会这样。但是,一旦我开始滚动集合视图,然后调用"viewForSupplementaryElementOfKind",我能够看到补充标题视图中的更新,正如我根据核心数据更改所期望的那样。此方法也会在初始创建 UICollectionView 时成功调用。
我有一个自定义布局,我正在与我的集合视图一起使用,所以问题可能出在那里?我希望有人能发现我的错误。
以下是用于创建 UICollectionView、其布局、单元格和标题视图的代码:
创建 UI 链接视图
- (void)createCollectionView { _layout1 = [[BigLayout alloc] init]; //custom layout [_layout1 setScrollDirection:UICollectionViewScrollDirectionHorizontal]; _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout1]; _collectionView.translatesAutoresizingMaskIntoConstraints = NO; _collectionView.backgroundColor = [UIColor clearColor]; _collectionView.dataSource = self; _collectionView.delegate = self; [self.view addSubview:_collectionView]; //set up constraints, add them to view... [self.collectionView registerClass:[InboxCell class] forCellWithReuseIdentifier:@"inbox"]; [self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header"]; }
创建自定义布局
@implementation BigLayout -(id)init { self = [super init]; if (self) { self.itemSize = CGSizeMake(330, 588); self.scrollDirection = UICollectionViewScrollDirectionHorizontal; self.headerReferenceSize = CGSizeMake(13, 13); } return self; } -(void)prepareLayout { [super prepareLayout]; _cellCount = [[self collectionView] numberOfItemsInSection:0]; } - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path { UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path]; attributes.size = self.itemSize; attributes.center = CGPointMake(path.item * (self.itemSize.width + 20) + self.itemSize.width/2.0 + 20, self.collectionView.center.y); return attributes; } - (CGSize)collectionViewContentSize { return CGSizeMake(((self.itemSize.width + 20) * _cellCount) + 80, [self collectionView].height); } -(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect { NSMutableArray* attributes = [NSMutableArray array]; for (NSInteger i=0 ; i < self.cellCount; i++) { NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:0]; UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:indexPath]; UICollectionViewLayoutAttributes *hattr = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath]; if (CGRectIntersectsRect(attr.frame, rect)) { [attributes addObject:attr]; [attributes addObject:hattr]; } } return attributes; } - (void)prepareForCollectionViewUpdates:(NSArray *)updateItems { } - (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath { UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath]; attributes.alpha = 1.0; return attributes; } - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:indexPath]; attributes.size = CGSizeMake(13, 13); attributes.center = CGPointMake(indexPath.item * (self.itemSize.width + 20) + self.itemSize.width/2.0 + 20 + self.collectionView.left, self.collectionView.height == 768 ? 75 : 200); attributes.alpha = 1.0f; return attributes; }
单元格的数据源方法(在 CD 更新中调用)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { //this method gets called on reload items InboxCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"inbox" forIndexPath:indexPath]; Email *email = [self.fetchedResultsController objectAtIndexPath:indexPath]; //do stuff with the email in the cell return cell; }
补充标头视图的数据源方法(在 CD 更新时不调用)
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { //this method does not get called on reload items, only gets called initially and on scroll UICollectionReusableView *reusableView; if (kind == UICollectionElementKindSectionHeader) { //specify in case we add a footer later UICollectionReusableView *unreadEmailImageIdentifier = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header" forIndexPath:indexPath]; Email *email = [self.fetchedResultsController objectAtIndexPath:indexPath]; UIImageView *unreadEmailDot = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"dot.png"]]; [unreadEmailImageIdentifier addSubview:unreadEmailDot]; unreadEmailImageIdentifier.hidden = YES; if (email.isUnread == YES || email.isUnread == 1) { unreadEmailImageIdentifier.hidden = NO; } reusableView = unreadEmailImageIdentifier; } return reusableView; }
简而言之,当我尝试重新加载集合视图或集合视图的组件时,似乎不会调用补充标题视图的数据源方法。但是,我确实看到调用了在自定义布局类中为补充视图创建属性的方法。如果有人可以指出任何可能的原因,这可能是发生,我将不胜感激!
reloadItemsAtIndexPaths
仅用于重新加载单元格。您可以通过使用 reloadSections:
重新加载部分来重新加载补充视图。如果您仍然遇到问题,请在问题中包含您在NSFetchedResultsControllerDelegate
实现中的问题。