ios - UICollectionView Section Header 坚持某个 Y

标签 ios objective-c uicollectionview uicollectionviewlayout

我正在尝试复制一个场景,其中我有一个一直到顶部的 Collection View ,一个位于 Collection View 第一行顶部的标题 View ,然后是一个标题部分 View (对于 indexPath.section == 1 ) 坚持标题 View 而不重叠或在其下方。

我实现了一个自定义布局,使标题具有粘性。但我不能让它粘在标题 View 上(所以在它的 origin.y+height 之后),它会粘在 Collection View 的顶部。

这是我的 IB 结构:

enter image description here

链接自定义布局:

enter image description here

这是理想的场景:

滚动前:

enter image description here

滚动后:

enter image description here

这是我的代码:

    @implementation LLCollectionCustomFlowLayout

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return YES;
}

- (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) {
            [missingSections addIndex: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 != nil) {
            [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;
        CGPoint const contentOffset = cv.contentOffset;
        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 { // UICollectionViewScrollDirectionHorizontal
            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;
}

@end

最佳答案

问题在这里:

frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y), nextHeaderOrigin.y - CGRectGetHeight(frame));

当表头是最后一个时,nextHeaderOrigin = CGPointMake(INFINITY, INFINITY)。这就是为什么 frame.origin.y 将是 MAX(contentOffset.y, frame.origin.y) 并固定在 Collection View 的顶部。您应该按以下方式更新 layoutAttributesForSupplementaryViewOfKind:

- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
        // for the header in the section #0, we have "sticky" behaviour by default
        if (indexPath.section == 0) {
            return attributes; 
        }
        CGPoint contentOffset = self.collectionView.contentOffset;
        UICollectionViewLayoutAttributes *prevHeaderAttributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section - 1]];
        CGFloat prevHeaderMaxY = CGRectGetMaxY(prevHeaderAttributes.frame); // The maximum Y value from the previous header should be the position we use to "stick" the current one
        CGFloat prevHeaderMaxX = CGRectGetMaxX(prevHeaderAttributes.frame);
        CGRect frame = attributes.frame;
        if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
            frame.origin.y = MAX(frame.origin.y, prevHeaderMaxY);
        }
        else { // UICollectionViewScrollDirectionHorizontal
            frame.origin.x = MAX(frame.origin.x, prevHeaderMaxX);
        }
        attributes.frame = frame;
    }
    return attributes;
}

关于ios - UICollectionView Section Header 坚持某个 Y,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31786564/

相关文章:

ios - 动画化 UICollectionView/UITableView 中 ScrollView 的偏移会导致单元格过早消失

ios - Swift 3/如何将 Root 的 UINavigationBar 与 UIViewController 的 UINavigationBar 重叠

ios - 使用 swift 集成 stripe SDK

objective-c - 我的 Cocoa 应用程序如何收到 WebView 中的 onClick 事件通知?

iphone - 是否有用于随机性的 Mersenne Twister 算法的稳定 Objective-C 实现?

ios - 如何突出显示 UICollectionView 单元格中的图像?

ios - 如何在 iOS Swift 3 中以编程方式创建 UICollectionView 类而不使用 Storyboard?

ios - willPresentNotification 无法按预期工作

iOS Today 扩展创建为 .app 而不是 .appex

ios - 在 ios 中使用 AVAudioSession 时出错