Erika Electra
Erika Electra

Reputation: 1882

iOS UICollectionView header & footer location

Working in iOS 7, how does one specify where the header & footer boxes go in a UICollectionView?

I have a custom UICollectionViewFlowLayout. I have overwritten

-(void)prepareLayout

-(NSArray*) layoutAttributesForElementsInRect:(CGRect)rect

-(UICollectionViewLayoutAttributes*) layoutAttributesForSupplementaryViewOfKind: (NSString*)kind atIndexPath:(NSIndexPath*)indexPath

My problem is, I'm not sure how to specify header location. I have already specified that a header exists in prepareLayout:

-(void)prepareLayout
{
[super prepareLayout];

boundsSize = self.collectionView.bounds.size;
midX = boundsSize.width / 2.0f;
curIndex = 0;

self.headerReferenceSize = CGSizeMake(CELL_SIZE, TITLE_HEIGHT);
self.footerReferenceSize = CGSizeMake(0, 0);

self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.sectionInset = UIEdgeInsetsMake(TOP_INSET, LEFT_INSET, BOTTOM_INSET, RIGHT_INSET);
self.minimumLineSpacing = LINE_SPACING;
self.minimumInteritemSpacing = INTERIM_SPACING;
self.itemSize = CGSizeMake(CELL_SIZE, CELL_SIZE);

}

I just don't know the right property of my custom FlowLayout to set, as there doesn't seem to be something like "HeaderLocation" to set, either as a LayoutAttributes or in the layout object itself. Right now, it is appearing to the side/between my images, when I'd like them to be appearing above each image (horizontal scroll).

I have tried the following:

-(UICollectionReusableView*) collectionView: (UICollectionView*)collectionView viewForSupplementaryElementOfKind:(NSString*)kind atIndexPath:(NSIndexPath*)indexPath
{
    NSLog(@"**ViewForSupplementaryElementOfKind called***");

    CGFloat centerX = collectionView.center.x;
    CGFloat centerY = collectionView.center.y;
    CGFloat titleWidth = [MyLayout titleWidth];
    CGFloat titleHeight = [MyLayout titleHeight];

    MyTitleView* titleView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:ImageTitleIdentifier forIndexPath:indexPath];

    titleView.frame = CGRectMake(centerX - titleWidth/2.0,
                                 0.0,
                                 titleWidth,
                                 titleHeight);

    return titleView;
}

This doesn't work. The title appears above overlapped with a bunch of other titles, then the moment I start scrolling (horizontally), they jump back into the wrong place, horizontally between the images rather than above.

PS> Please do not suggest anything that has to do with NIB or XIB placement. I am using a UICollectionView, NOT a UICollectionViewController, so I actually have no prototypical cell to work with. The layout is being done entirely programatically -- from code alone -- so I can't simply open a XIB file and adjust the location of a text box.

Upvotes: 0

Views: 7314

Answers (2)

Kirit Modi
Kirit Modi

Reputation: 23407

CollectionView Header height is set below Collectionview delegate

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section

And Set view in Collectionview Header in Below Delegate

- (UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    UICollectionReusableView * view = nil;

    if ([kind isEqualToString:UICollectionElementKindSectionHeader])
    {
        ColorSectionHeaderView *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                                                                            withReuseIdentifier:NSStringFromClass([ColorSectionHeaderView class])
                                                                                   forIndexPath:indexPath];
        header.sectionIndex = indexPath.section;
        header.hideDelete = collectionView.numberOfSections == 1; // hide when only one section
        header.delegate = self;
        view = header;
    }

return view;

}

Ragistred Class in ViewDidLoad

-(void)ViewDidLoad
{

[collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([ColorSectionFooterView class]) bundle:nil]
     forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
            withReuseIdentifier:NSStringFromClass([ColorSectionFooterView class])];

   [Super ViewDidLoad];
}

Upvotes: -2

followben
followben

Reputation: 9197

Amending the attributes returned by -layoutAttributesForElementsInRect is the right approach, but if you want to alter the position of offscreen headers and footers, you may need to fetch the supplementary view attributes yourself.

For example, in your UICollectionViewFlowLayout subclass:

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray *attributesArray = [[super layoutAttributesForElementsInRect:rect] mutableCopy];

    // the call to super only returns attributes for headers that are in the bounds,
    // so locate attributes for out of bounds headers and include them in the array
    NSMutableIndexSet *omittedSections = [NSMutableIndexSet indexSet];
    for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
        if (attributes.representedElementCategory == UICollectionElementCategoryCell) {
            [omittedSections addIndex:attributes.indexPath.section];
        }
    }
    for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
        if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
            [omittedSections removeIndex:attributes.indexPath.section];
        }
    }
    [omittedSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];
        UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                                                                                            atIndexPath:indexPath];
        [attributesArray addObject:attributes];
    }];

    for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
        if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {

            // adjust any aspect of each header's attributes here, including frame or zIndex

        }
    }

    return attributesArray;
}

Upvotes: 0

Related Questions