How to use UITableViewHeaderFooterView?
Hi I want to use UITableHeaderFooterView
in my app and i am doing this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[_tableView registerClass:[M3CTableViewCell class] forCellReuseIdentifier:@"cell"];
[_tableView registerClass:[M3CHeaderFooter class] forHeaderFooterViewReuseIdentifier:@"footer"];
}
- (UITableViewHeaderFooterView *)footerViewForSection:(NSInteger)section {
M3CHeaderFooter * footer = [[M3CHeaderFooter alloc]initWithReuseIdentifier:@"footer"];
footer.textLabel.text = @"Test";
return footer;
}
By doing this I am not getting anything at Footer's place.
And this method is not even getting called but I think this method is part of UITableViewDelegate
protocol.
Solution 1:
Using the new iOS 6 feature of reusable header/footer views involves two steps. You seem to be doing only the first step.
First step: you're telling the table view what class to use for the section header view, by registering your custom subclass of UITableViewHeaderFooterView (I assume your M3CHeaderFooter is a subclass of UITableViewHeaderFooterView).
Second step: Tell the table view what view to use (AND reuse) for a header section by implementing the tableView delegate method
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
So in your viewDidLoad you'd implement something like this:
// ****** Do Step One ******
[_tableView registerClass:[M3CHeaderFooter class] forHeaderFooterViewReuseIdentifier:@"TableViewSectionHeaderViewIdentifier"];
Then you'd implement the table View delegate method in the class where you're creating and displaying your table view:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 40.0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
static NSString *headerReuseIdentifier = @"TableViewSectionHeaderViewIdentifier";
// ****** Do Step Two *********
M3CHeaderFooter *sectionHeaderView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
// Display specific header title
sectionHeaderView.textLabel.text = @"specific title";
return sectionHeaderView;
}
Now mind you that you do not need to subclass UITableViewHeaderFooterView in order to use it. Before iOS 6, if you wanted to have a header view for a section, you'd implement the above tableView delegate method and tell the table view what view to use for each section. So each section had a different instance of a UIView which you provided. This means that if your tableView had 100 sections, and inside the delegate method you created a new instance of a UIView, then you would have given the tableView 100 UIViews for the 100 section headers that were displayed.
Using the new feature of reusable header/footer views, you create an instance of a UITableViewHeaderFooterView and the system reuses it for each displayed section header.
If you wanted to have a reusable UITableViewHeaderFooterView without subclassing then you simply change your viewDidLoad to this:
// Register the class for a header view reuse.
[_buttomTableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"TableViewSectionHeaderViewIdentifier"];
and then your delegate method to this:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 40.0;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
static NSString *headerReuseIdentifier = @"TableViewSectionHeaderViewIdentifier";
// Reuse the instance that was created in viewDidLoad, or make a new one if not enough.
UITableViewHeaderFooterView *sectionHeaderView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
sectionHeaderView.textLabel.text = @"Non subclassed header";
return sectionHeaderView;
}
I hope that was clear enough.
EDIT: When subclassing the header view, you can implement code similar to the following if you wish to add a custom view to the headerView:
// Add any optional custom views of your own
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 30.0)];
[customView setBackgroundColor:[UIColor blueColor]];
[sectionHeaderView.contentView addSubview:customView];
Doing this in the subclass, as opposed to viewForHeaderInSection: delegate method (as noted below by Matthias), will ensure that only one instance of any subviews are created. You can then add any properties within the subclass that will allow you to access your custom subview.
Solution 2:
UITableViewHeaderFooterView is one of the few places I would programmatically handle the view rather than use Storyboard or a XIB. Since you cannot officially use appearance proxy and there is no IB way to do it without abusing UITableViewCells. I do it the old-fashioned way and just use the tag on the label to fetch the custom elements.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kSectionHeaderReuseIdentifier];
if (headerView == nil) {
[tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:kSectionHeaderReuseIdentifier];
headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kSectionHeaderReuseIdentifier];
}
UILabel *titleLabel = (UILabel *)[headerView.contentView viewWithTag:1];
if (titleLabel == nil) {
UIColor *backgroundColor = [UIColor blackColor];
headerView.contentView.backgroundColor = backgroundColor;
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 0.0f, 300.0f, 44.0f)];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.backgroundColor = backgroundColor;
titleLabel.shadowOffset = CGSizeMake(0.0f, 0.0f);
titleLabel.tag = 1;
titleLabel.font = [UIFont systemFontOfSize:24.0f];
[headerView.contentView addSubview:titleLabel];
}
NSString *sectionTitle = [self.sections objectAtIndex:section];
if (sectionTitle == nil) {
sectionTitle = @"Missing Title";
}
titleLabel.text = sectionTitle;
return headerView;
}