У меня есть UICollectionView, контент для которого предоставляется NSFetchedResultsController. Всякий раз, когда основные данные обновляются, выполняется вызов для обновления измененных элементов в представлении коллекции с помощью метода reloadItemsAtIndexPaths:.
После большого количества тестов я определил, что описанный выше процесс работает правильно. Я обновляю основные данные, и в конечном итоге вызывается метод источника данных «cellForItemAtIndexPath», и ячейки обновляются, как и ожидалось. Однако я также реализовал метод источника данных viewForSupplementaryElementOfKind для отображения некоторых заголовков ячеек (также на основе изменений в основных данных), и это не работает должным образом.
По какой-то причине кажется, что когда 'reloadItemsAtIndexPaths' вызывается после изменения основных данных, 'viewForSupplementaryElementOfKind' не вызывается, и я не могу понять, почему это так. Однако, как только я начинаю прокручивать представление коллекции, ТОГДА вызывается viewForSupplementaryElementOfKind, и я могу видеть обновления в дополнительных представлениях заголовков, как и ожидалось, на основе изменений основных данных. Этот метод также успешно вызывается при первоначальном создании UICollectionView.
У меня есть собственный макет, который я использую с представлением коллекции, и, возможно, проблема заключается в нем? Я надеюсь, что кто-то может заметить мою ошибку.
Вот код для создания UICollectionView, его макета, ячеек и его заголовков:
Создать UICollectionView
- (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; }
Метод DataSource для ячеек (вызывается в обновлениях компакт-диска)
- (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; }
Короче говоря, когда я пытаюсь перезагрузить представление коллекции или компоненты представления коллекции, метод источника данных для дополнительных представлений заголовков не вызывается. Однако я вижу, что вызывается метод создания атрибутов для дополнительного представления в пользовательском классе макета. Если кто-то может указать любую возможную причину, по которой это может происходить, я был бы признателен!