Hi I want to use UITableHeaderFooterView
in my app and i am doing this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional
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;
}
Here is a "quick-and-dirty" way to get this going. It will make a small blue label in the header. I've confirmed that this renders OK in iOS 6 and iOS 7.
in your UITableViewDelegate:
-(void)viewDidLoad
{
...
[self.table registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"Header"];
...
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 34.;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UITableViewHeaderFooterView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"Header"];
UILabel *leftlabel = [[UILabel alloc] initWithFrame:CGRectMake(0., 0., 400., 34.)];
[leftlabel setBackgroundColor:[UIColor blueColor]];
[header.contentView addSubview:leftlabel];
return header;
}
One of the reasons that method may not be being called is the style of the table. Standard vs Grouped handles headers/footers differently. That may explain why it's not getting called.
This is an old post and has good answers, but I wanted to share another work-around for a very similar issue I experienced.
At first, I used:
-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
With a custom prototype cell for my header view. Subclassing UITableViewCell as such
static NSString *cellIdentifier = @"CustomHeaderCell";
CustomHeaderCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
However, when animating TableView cells above section headers (making them twice as tall) the header view would disappear. This, as pointed out, is because the implementation only supplied a view, not a re-usable view.
Instead of forgoing everything with the customized prototype cell, I implemented the UITableViewHeaderFooterWithIdentifier and set it as the prototyped cell's contentView, without subclassing UITableViewHeaderFooterWithIdentifier.
static NSString *customHeaderViewIdentifier = @"CustomHeaderView";
UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:customHeaderViewIdentifier];
headerView = (UITableViewHeaderFooterView *)cell.contentView;
I realize this creates two instances of the header view (at least I think it would..) however it does allow you to keep the benefits of a customized prototype cell without doing everything programatically.
Full code:
// viewDidLoad
[myTableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:@"CustomHeaderView"];
// Implement your custom header
-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
static NSString *cellIdentifier = @"CustomHeaderCell";
CustomHeaderCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
static NSString *customHeaderViewIdentifier = @"CustomHeaderView";
UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:customHeaderViewIdentifier];
// do your cell-specific code here
// eg. cell.myCustomLabel.text = @"my custom text"
headerView = (UITableViewHeaderFooterView *)cell.contentView;
return headerView;
}
Set delegate
property of UITableView
instance to reference to the controller that implements next methods:
Method that returns view of section footer:
Asks the delegate for a view object to display in the footer of the specified section of the table view.
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
Height of view in section footer:
Asks the delegate for the height to use for the footer of a particular section.
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:
(NSInteger)section
There are a few ways of approaching this, but here is one a solution in Swift: the idea here is that we have a subclass of UITableViewHeaderFooterView
called SNStockPickerTableHeaderView
; it exposes a method called, configureTextLabel()
that when called, sets the font and the color of the text label. We call this method only after the title has been set, that is from, willDisplayHeaderView
, and the font gets correctly set.
The header view also supports a custom line separator to set it apart from the rest of the cells.
// MARK: UITableViewDelegate
func tableView(tableView:UITableView, willDisplayHeaderView view:UIView, forSection section:Int) {
if let headerView:SNStockPickerTableHeaderView = view as? SNStockPickerTableHeaderView {
headerView.configureTextLabel()
}
}
func tableView(tableView:UITableView, viewForHeaderInSection section:Int) -> UIView? {
var headerView:SNStockPickerTableHeaderView? = tableView.dequeueReusableHeaderFooterViewWithIdentifier(kSNStockPickerTableHeaderViewReuseIdentifier) as? SNStockPickerTableHeaderView
if (headerView == nil) {
// Here we get to customize the section, pass in background color, text
// color, line separator color, etc.
headerView = SNStockPickerTableHeaderView(backgroundColor:backgroundColor,
textColor:primaryTextColor,
lineSeparatorColor:primaryTextColor)
}
return headerView!
}
And here is the custom UITableViewHeaderFooterView
:
import Foundation
import UIKit
private let kSNStockPickerTableHeaderViewLineSeparatorHeight:CGFloat = 0.5
private let kSNStockPickerTableHeaderViewTitleFont = UIFont(name:"HelveticaNeue-Light", size:12)
let kSNStockPickerTableHeaderViewReuseIdentifier:String = "stock_picker_table_view_header_reuse_identifier"
class SNStockPickerTableHeaderView: UITableViewHeaderFooterView {
private var lineSeparatorView:UIView?
private var textColor:UIColor?
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// We must implement this, since the designated init of the parent class
// calls this by default!
override init(frame:CGRect) {
super.init(frame:frame)
}
init(backgroundColor:UIColor, textColor:UIColor, lineSeparatorColor:UIColor) {
super.init(reuseIdentifier:kSNStockPickerTableHeaderViewReuseIdentifier)
contentView.backgroundColor = backgroundColor
self.textColor = textColor
addLineSeparator(textColor)
}
// MARK: Layout
override func layoutSubviews() {
super.layoutSubviews()
let lineSeparatorViewY = CGRectGetHeight(self.bounds) - kSNStockPickerTableHeaderViewLineSeparatorHeight
lineSeparatorView!.frame = CGRectMake(0,
lineSeparatorViewY,
CGRectGetWidth(self.bounds),
kSNStockPickerTableHeaderViewLineSeparatorHeight)
}
// MARK: Public API
func configureTextLabel() {
textLabel.textColor = textColor
textLabel.font = kSNStockPickerTableHeaderViewTitleFont
}
// MARK: Private
func addLineSeparator(lineSeparatorColor:UIColor) {
lineSeparatorView = UIView(frame:CGRectZero)
lineSeparatorView!.backgroundColor = lineSeparatorColor
contentView.addSubview(lineSeparatorView!)
}
}
Here is the result, see section header for, "Popular Stocks":