Я использую это решение для создания липких заголовков в вид коллекции, и он хорошо работает на iOS6. Но в iOS7, если установлен флажок «Расширить края под верхними полосами», то заголовок придерживается исходной точки представления, которая затем находится за панелью навигации.

Так что на данный момент я отключил эту опцию, но мне бы очень хотелось настроить это решение, чтобы оно работало, когда края расширены (для получения приятного размытого эффекта, когда контент прокручивается за панелью навигации).

Кто-нибудь может мне с этим помочь? Или у кого-то есть другие предложения для достижения той же цели?

1
Alexis 27 Сен 2013 в 14:00
1
Похоже, вам нужно использовать topLayoutGuide?
 – 
Mike Pollard
27 Сен 2013 в 14:18

1 ответ

Лучший ответ

Вот мое полное решение. Просто добавьте в свой класс FlowLayout следующее:

#pragma mark STICKY HEADERS CODE BELOW
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy];

    NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];
    for (NSUInteger idx=0; idx<[answer count]; idx++) {
        UICollectionViewLayoutAttributes *layoutAttributes = answer[idx];

        if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell || layoutAttributes.representedElementCategory == UICollectionElementCategorySupplementaryView) {
            [missingSections addIndex:(NSUInteger) layoutAttributes.indexPath.section];  // remember that we need to layout header for this section
        }
        if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
            [answer removeObjectAtIndex:idx];  // remove layout of header done by our super, we will do it right later
            idx--;
        }
    }

//    layout all headers needed for the rect using self code
    [missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];
        UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
        if (layoutAttributes) {
            [answer addObject:layoutAttributes];
        }
    }];

    return answer;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
        UICollectionView * const cv = self.collectionView;

        CGFloat topOffset = 0;
        if ([self.collectionView.dataSource isKindOfClass:[UIViewController class]]) {
            UIViewController *collectionViewParentViewController = (UIViewController *)self.collectionView.dataSource;
            topOffset = collectionViewParentViewController.topLayoutGuide.length;
        }

        CGPoint const contentOffset = CGPointMake(cv.contentOffset.x, cv.contentOffset.y + topOffset);
        CGPoint nextHeaderOrigin = CGPointMake(INFINITY, INFINITY);

        if (indexPath.section+1 < [cv numberOfSections]) {
            UICollectionViewLayoutAttributes *nextHeaderAttributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section+1]];
            nextHeaderOrigin = nextHeaderAttributes.frame.origin;
        }

        CGRect frame = attributes.frame;
        if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
            frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y), nextHeaderOrigin.y - CGRectGetHeight(frame));
        }
        else {
            frame.origin.x = MIN(MAX(contentOffset.x, frame.origin.x), nextHeaderOrigin.x - CGRectGetWidth(frame));
        }
        attributes.zIndex = 1024;
        attributes.frame = frame;
    }

    return attributes;
}

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
    return attributes;
}

- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
    return attributes;
}

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {
    return YES;
}
8
Andrew Jackman 6 Дек 2013 в 18:44
1
Не могли бы вы подробнее рассказать о своем решении? Перетаскивание его в подкласс UICollectionViewFlowLayout, похоже, не работает.
 – 
Andrew Theis
26 Ноя 2013 в 02:44
Я обновил свой ответ, чтобы показать полную реализацию, в соответствии с просьбой @AndrewTheis
 – 
Andrew Jackman
6 Дек 2013 в 18:46
Это можно упростить и обобщить, просто используя contentInset представления коллекции вместо того, чтобы пытаться попасть в иерархию контроллера представления, чтобы получить topLayoutGuide.
 – 
Hilton Campbell
17 Июл 2015 в 02:54
Как вы можете видеть из даты моего первоначального ответа, он уже довольно старый. Не стесняйтесь размещать упрощенное решение @HiltonCampbell.
 – 
Andrew Jackman
28 Июл 2015 в 17:57