13

我创建了一个自定义UICollectionViewLayout,并将其放在情节提要中的 Collection View Controller 中。我在显示项目/单元格时没有遇到太多问题。我的问题是viewForSupplementaryElementOfKind没有被调用。我似乎无法确定为什么会这样。我试图回到默认布局,然后它确实调用了它,但我需要我的自定义UICollectionViewLayout. 我已经离开NSLogs 去检查并且viewForSupplementaryElementOfKind没有被调用。

这是我的 MyCollectionViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];

    // Do any additional setup after loading the view.
    viewArray = [NSMutableArray array];
    
    //setup the delegate for vertical flow layout
    [(VerticalFlowLayout*)self.collectionViewLayout setDelegate:self];
    
    //register the headers
    [self.collectionView registerNib:[ButtonHeaderCollectionReusableView nib] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:[ButtonHeaderCollectionReusableView reusableID]];
    
    //set the insets
    [self.collectionView setContentInset:UIEdgeInsetsMake(23, 5, 10, 5)];
}

#pragma mark - CollectionView DataSource

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return [self.cardsArray count];
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    NSLog(@"Number of Sections");
    return 1;
}

- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    
    NSLog(@"Making Card");
    
    CardCell *card = [collectionView dequeueReusableCellWithReuseIdentifier:@"CardCell" forIndexPath:indexPath];
    
    //    UILabel *cardLabel = [card viewWithTag:101];
    //    [cardLabel setText:[textArray objectAtIndex:[indexPath row]]];
    
    return card;
}

- (UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    
    NSLog(@"Making Header");
    
    UICollectionReusableView *reusableView = nil; /*[[UICollectionReusableView alloc] initWithFrame:CGRectMake(0, 0, 100, 75)];*/
    //    [reusableView setBackgroundColor:[UIColor blackColor]];
    
    if (kind == UICollectionElementKindSectionHeader) {
        ButtonHeaderCollectionReusableView *headerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:[ButtonHeaderCollectionReusableView reusableID] forIndexPath:indexPath];
        
        return headerview;
    }
    
    //    if (kind == UICollectionElementKindSectionFooter) {
    //        UICollectionReusableView *footerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath];
    //    }
    
    return reusableView;
}

- (CGSize)collectionView:collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
    return CGSizeMake(180.0f, 72.0f);
}

现在这是我的 MyFlowLayout.m

- (id)initWithCoder:(NSCoder *)aDecoder {
    NSLog(@"Vertical Flow Layout init with coder");
    if(self = [super initWithCoder:aDecoder]) {
        contentHeight = 0;
        cachedAttributes = [NSMutableArray array];
    }
    
    return self;
}

- (void)prepareLayout {
    NSLog(@"Preparing Layout");
    //    [super prepareLayout];
    
    contentWidth = CGRectGetWidth(self.collectionView.bounds) - (self.collectionView.contentInset.left + self.collectionView.contentInset.right);
    
    if([cachedAttributes count] == 0) {
        //compute for column width
        CGFloat columnWidth = contentWidth / NUMBER_OF_COLUMNS;
        NSMutableArray *xOffsets = [NSMutableArray array];
        for(int i = 0; i < NUMBER_OF_COLUMNS; i++) {
            [xOffsets addObject:[NSNumber numberWithFloat:(i * columnWidth)]];
        }
        
        //compute for height
        NSMutableArray *yOffsets = [NSMutableArray array];
        for(int i = 0; i < NUMBER_OF_COLUMNS; i++) {
            [yOffsets addObject:[NSNumber numberWithFloat:75]];
        }
        
        int column = 0;
        //loop through all the sections and items in the collectionview
        for(int i = 0; i < self.collectionView.numberOfSections; i++) {
            for(int j = 0; j < [self.collectionView numberOfItemsInSection:i]; j++) {
                NSIndexPath *indexPath = [NSIndexPath indexPathForItem:j inSection:i];
                
                //time to do some frame calculation
                ///let's start with the width
                CGFloat width = columnWidth - CELL_PADDING * 2;
                ///then the height
                CGFloat viewHeight = [self.delegate getViewHeightWithCollectionView:self.collectionView indexPath:indexPath withWidth:width];
                CGFloat height = CELL_PADDING + viewHeight + /*textHeight +*/ CELL_PADDING;
                
                CGFloat xOffset = [[xOffsets objectAtIndex:column] floatValue];
                CGFloat yOffset = [[yOffsets objectAtIndex:column] floatValue];
                
                CGRect frame = CGRectMake(xOffset, yOffset, columnWidth, height);
                CGRect insetFrame = CGRectInset(frame, CELL_PADDING, CELL_PADDING);
                
                //now that computation is done we shall make the attributes
                UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
                [attributes setFrame:insetFrame];
                [cachedAttributes addObject:attributes];
                
                //time to increment the height and the column
                contentHeight = MAX(contentHeight, CGRectGetMaxY(frame));
                NSNumber *yOffSetColumn = [yOffsets objectAtIndex:column];
                yOffSetColumn = [NSNumber numberWithFloat:([yOffSetColumn floatValue] + height)];
                [yOffsets replaceObjectAtIndex:column withObject:yOffSetColumn];
                
                NSLog(@"Content Height: %f yOffSetColumn: %@ == %@", contentHeight, yOffSetColumn, [yOffsets objectAtIndex:column]);
                
                column = column >= (NUMBER_OF_COLUMNS - 1) ? 0 : ++column;
            }
        }
    }
}

- (CGSize)collectionViewContentSize {
    //    NSLog(@"Collection View Content Size");
    return CGSizeMake(contentWidth, contentHeight + 75);
}

// called after preparelayout to determine which items are visible in the given rect
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSMutableArray<UICollectionViewLayoutAttributes *> *layoutAttributes = [NSMutableArray array];
    
    NSInteger sectionsCount = [self.collectionView.dataSource numberOfSectionsInCollectionView:self.collectionView];
    
    NSLog(@"Sections count: %ld", (long)sectionsCount);
    
    for(int i = 0; i < sectionsCount; i++) {
        //for header
        UICollectionViewLayoutAttributes *headerAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:i]];
    //        if(CGRectIntersectsRect(headerAttributes.frame, rect)) {
    //            NSLog(@"Adding Section Attribute");
            [layoutAttributes addObject:headerAttributes];
    //        }
        
        for (UICollectionViewLayoutAttributes *attributes in cachedAttributes) {
            if(CGRectIntersectsRect(attributes.frame, rect)) {
                [layoutAttributes addObject:attributes];
            }
        }
        
    //        NSInteger itemsCount = [self.collectionView numberOfItemsInSection:i];
    //        for(int j = 0; j < itemsCount; j++) {
    //            UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:j inSection:i]];
    //            if(CGRectIntersectsRect(attributes.frame, rect)) {
    //                [layoutAttributes addObject:attributes];
    //            }
    //        }
    }
    
    return layoutAttributes;
}

//- (UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
//    NSLog(@"Layout Attributes For Item: %ld %ld", [indexPath row], [indexPath section]);
//    
//    UICollectionViewLayoutAttributes *attributes = [cachedAttributes objectAtIndex:[indexPath row]];
//    return attributes;
//}
    
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath {
    
    NSLog(@"Layout Attributes For Header: %@ %ld %ld", elementKind, [indexPath row], [indexPath section]);
    
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    [attributes setFrame:CGRectMake(0, 0, contentWidth /*320*/, 75.0f)];
    
    return attributes;
}

正如您在 MyFlowLayout 中看到的那样,有些事情我已经尝试过,但仍然没有调用viewForSupplementaryElementOfKind. 我尝试实施layoutAttributesForItemAtIndexPath,因为我有layoutAttributesForSupplementaryViewOfKind. 我还尝试使用您看到的固定数字(例如 75 和 320)来检查是否会生成标题。你看到的委托,它只是为了获得一个视图的高度。

因为我已经为标题提供了足够的空间以供查看,并且将 NSLogs 全部留下,但(UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath没有被调用。

以下是我查看并尝试过的一些内容:stackoverflow,但正如您从我包含的注释代码中看到的那样。它仍然没有工作。

谢谢您的帮助。

4

2 回答 2

12

我也有这个问题,我的解决方案是简单地为 prepareLayout 中的部分添加属性

UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
attributes.frame = CGRectMake(0, 0, self.collectionView.frame.size.width, 100);
[cachedAttributes addObject:attributes];
于 2016-06-23T18:00:15.410 回答
11

添加标题部分的默认大小:

collectionViewLayout.headerReferenceSize = CGSize(width, height)

默认大小值为 (0, 0)。这就是标题不显示的原因。

或者

还有另一种方法,实现 UICollectionView 的委托方法:

collectionView(_:layout:referenceSizeForFooterInSection:)
于 2017-07-31T06:23:22.577 回答