How to hide first section header in UITableView (grouped style)

Codo picture Codo · Sep 27, 2013 · Viewed 111.2k times · Source

As the design of table views using the grouped style changed considerably with iOS 7, I would like to hide (or remove) the first section header. So far I haven't managed to achieve it.

Somewhat simplified, my code looks like this:

- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section == 0)
        return 0.0f;
    return 32.0f;
}

- (UIView*) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        UIView* view = [[UIView alloc] initWithFrame: CGRectMake(0.0f, 0.0f, 640.0f, 0.0f)];
        return view;
    }
    return nil;
}

- (NSString*) tableView:(UITableView *) tableView titleForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return nil;
    } else {
        // return some string here ...
    }
}

If I return a height of 0, the other two methods will never be called with the section index 0. Yet an empty section header is still drawn with the default height. (In iOS 6, the two methods are called. However, the visible result is the same.)

If I return a different value, the section header gets the specified height.

If I return 0.01, it's almost correct. However, when I turn on "Color Misaligned Images" in the simulator, it marks all table view cells (which seems to be a logical consequence).

The answers to the question UITableView: hide header from empty section seem to indicate that some people were successful in hiding the section header. But it might apply to the plain style (instead of the grouped one).

The best compromise so far is returning the height 0.5, resulting in a somewhat thicker line below the navigation bar. However, I'd appreciate if somebody knows how the first section header can be completely hidden.

Update

According to caglar's analysis (https://stackoverflow.com/a/19056823/413337), the problem only arises if the table view is contained in a navigation controller.

Answer

Codo picture Codo · Sep 27, 2013

I have a workaround that seems reasonably clean to me. So I'm answering my own question.

Since 0 as the first section header's height doesn't work, I return 1. Then I use the contentInset to hide that height underneath the navigation bar.

Objective-C:

- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section == 0)
            return 1.0f;
    return 32.0f;
}

- (NSString*) tableView:(UITableView *) tableView titleForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return nil;
    } else {
        // return some string here ...
    }
}

- (void) viewDidLoad
{
    [super viewDidLoad];

     self.tableView.contentInset = UIEdgeInsetsMake(-1.0f, 0.0f, 0.0f, 0.0);
}

Swift:

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return section == 0 ? 1.0 : 32
}

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.contentInset = UIEdgeInsets(top: -1, left: 0, bottom: 0, right: 0)
}