user1118321
user1118321

Reputation: 26375

NSCollectionView header display

I have an NSCollectionView that has 3 sections which contains colors from a color palette. I want each section to have a header view with the name of the section. At first glance, it appears to work. On launch, it looks like this:

A window showing various colors grouped by type, such as Bright Colors, and Pastel Colors

However, as soon as I resize the window, the header text ends up drawing outside the headers (and also inside it, somehow!):

The color palette again with the header text drawn incorrectly.

In order to have headers in the collection view, I have a header view class named CollectionHeaderView. I register this class as a supplemental view:

    [_collection registerClass:[CollectionHeaderView class]
    forSupplementaryViewOfKind:@"UICollectionElementKindSectionHeader"
                withIdentifier:kSupplementalView];

In the collection view's delegate, I implement the method to return the view for the supplemental element:

- (NSView *)collectionView:(NSCollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
               atIndexPath:(NSIndexPath *)indexPath {
    NSView* result = [collectionView makeSupplementaryViewOfKind:kind
                                                  withIdentifier:kSupplementalView
                                                    forIndexPath:indexPath];

    if ([kind isEqualToString:@"UICollectionElementKindSectionHeader"]) {
        NSTextField* textView = ((CollectionHeaderView*)result).textField;
        switch (indexPath.section) {
            case 0:
                [textView setStringValue:@"Bright Colors"];
                break;

            case 1:
                [textView setStringValue:@"Pastel Colors"];
                break;

            case 2:
                [textView setStringValue:@"Designer Colors"];
                break;
        }

        return textView;
    }

    return nil;
}

Furthermore, if I resize the window, the header views do not move. The collection elements seem to flow around the headers, leaving things listed under the wrong section. And, as you can see in the second picture above, widening the window ends up leaving a gap between the right edge of the header and the right edge of the collection view.

The CollectionHeaderView class is very simple. It just creates a text field and draws the background and the text field:

@implementation CollectionHeaderView

- (instancetype)initWithFrame:(NSRect)frameRect {
    self = [super initWithFrame:frameRect];

    if (self != nil) {
        NSRect textFrame = frameRect;
        _textField = [[NSTextField alloc] initWithFrame:textFrame];
        _textField.editable = NO;
        _textField.bordered = NO;
        _textField.font = [NSFont fontWithName:@"Helvetica-Bold" size:14.0];
        _textField.backgroundColor = [NSColor colorWithSRGBRed:0.0 green:0.0 blue:0.0 alpha:0.0];
        [self addSubview:_textField];

        self.identifier = kSupplementalView;
    }

    return self;
}

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];

    // Drawing code here.
    NSBezierPath*   fillPath    = [NSBezierPath bezierPath];
    [fillPath appendBezierPathWithRect:dirtyRect];
    [[NSColor lightGrayColor] setFill];
    [fillPath fill];

    [_textField drawRect:dirtyRect];
}

@end

Have I implemented any of the above methods incorrectly? Is there any method I need to implement that I haven't?

Upvotes: 1

Views: 459

Answers (1)

Willeke
Willeke

Reputation: 15598

The return value of collectionView:viewForSupplementaryElementOfKind:atIndexPath: is the supplementary view result.

- (NSView *)collectionView:(NSCollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
               atIndexPath:(NSIndexPath *)indexPath {
    NSView* result = [collectionView makeSupplementaryViewOfKind:kind
                                                  withIdentifier:kSupplementalView
                                                    forIndexPath:indexPath];

    if ([kind isEqual:NSCollectionElementKindSectionHeader]) {
        NSTextField* textView = ((CollectionHeaderView*)result).textField;
        switch (indexPath.section) {
            case 0:
                [textView setStringValue:@"Bright Colors"];
                break;

            case 1:
                [textView setStringValue:@"Pastel Colors"];
                break;

            case 2:
                [textView setStringValue:@"Designer Colors"];
                break;
        }

        return result;
    }

    return nil;
}

Upvotes: 3

Related Questions