ios - 如何在 iOS7 上的 UICollectionView 中制作粘性标题?

标签 ios ios7 uicollectionview uicollectionviewlayout

我正在使用 this solution在 Collection View 中制作粘性标题,它在 iOS6 上运行良好。但是在 iOS7 中,如果选中了“在顶部栏下延伸边缘”选项,则标题会粘在 View 的原点上,然后位于导航栏的后面。

所以现在我禁用了该选项,但我真的很想调整该解决方案以使其在边缘扩展时工作(以便在内容滚动到导航栏后面时具有良好的模糊效果)。

有人可以帮我吗?或者是否有人有任何其他建议来实现相同的目标?

最佳答案

这是我的完整解决方案。只需将以下内容添加到您的 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;
}

关于ios - 如何在 iOS7 上的 UICollectionView 中制作粘性标题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19047972/

相关文章:

ios - View转到Table View,表格不起作用

ios - 创建新的 Swift 包 - 找不到 header

swift - 两个不同单元格的 TableView 相同的 cellForRowAt 用法

ios - 如何在 2 个不同的 UICollectionViewFlowLayout 实例之间切换?

swift - 更改 UICollectionViewCell 内项目的大小

ios - 为从 firestore 加载数据创建结构或类

ios - 在 iOS GCD 中调用 DispatchQueue.main.async 的成本

ios - Apple 的 Controller 在 iOS7 中无法正确显示

ios - 当键盘关闭时,如何使搜索栏中的取消按钮保持启用状态?

ios - 如何让 gif 在 UIWebView 中永不停止?