user
user

Reputation: 3456

How can I reuse a single xib as a tableview's section header?

I'd like to leverage Apple's locking section header control on my tableview (where the section header sticks to the top until pushed upward by the next section header), but I'd like to use my own view, and one that I design by xib.

Elsewhere in my app, I create views in code for the section headers and all is well, but when trying to do the same thing with a xib for a view, it gets problematic.

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    ProductSectionHeader* header = self.productHeaderView;
    if (!header)
    {
        [[NSBundle mainBundle] loadNibNamed:@"ProductSectionHeader" owner:self options:nil];
    }
    header.nameLabel.text = @"Some person";
    header.locationLabel.text = @"Some place";

    return header;
}

This shows the header view in the first section (each cell has it's own section) but then all headers disappear when the second header is prompted to show. It seems that I'm only allowed one reference to the xib or something.

So how do I reuse a xib to create multiple instances of that view in one controller, and how do I employ that into section headers?

Upvotes: 0

Views: 398

Answers (2)

Caleb
Caleb

Reputation: 125007

So how do I reuse a xib to create multiple instances of that view in one controller, and how do I employ that into section headers?

A new copy of the view is created each time you load the .xib. The trick is to save the newly loaded view in a different property or variable and then clear the outlet connected to the view so that you can load another copy. So, something like this, assuming productHeaderView is an outlet connected to the header view:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    // load the view from the .xib
    [[NSBundle mainBundle] loadNibNamed:@"ProductSectionHeader" owner:self options:nil];

    // save it in a different variable
    ProductSectionHeader* header = self.productHeaderView;

    // clear the outlet for next time
    self.productHeaderView = nil;

    if (!header)
    {
        NSLog(@"There was a problem loading the view.")
    }
    header.nameLabel.text = @"Some person";
    header.locationLabel.text = @"Some place";

    return header;
}

I should also point out the relatively new UITableView method -registerNib:forHeaderFooterViewReuseIdentifier:, which makes things even easier. You can just register a nib object with the table and let the table worry about loading the view. There's a similar method for table cells.

Upvotes: 2

Gavin
Gavin

Reputation: 8200

In the line where you call loadNibNamed:, you're not doing anything with the result of that line. It returns an NSArray containing the views from that xib file, which you're not saving. You never set header to anything in your if statement. Assuming that xib contains only the one UIView that you want, you would want to get the item at index 0 from that array.

Also, the fact that you're seeing a header in the first place implies to me that self.productHeaderView is already set to something somewhere else in your code, so it never goes into your if statement in the first place. So I'm guessing you're seeing the issue you're seeing because it is trying to use the same UIView as the header for every section, and it's causing issues because it's trying to place it in multiple spots.

If you want to fix this, make sure that you're using a unique UIView for each section, so you shouldn't be trying to store and retrieve a single UIView in an instance variable like you are, unless you only had one section. You could maybe replace that with an NSMutableDictionary, so that you create and store a header for each section only once, and subsequent calls to this will just retrieve it from the dictionary.

Upvotes: 2

Related Questions