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

IosUitableviewIos7

Ios Problem Overview


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 https://stackoverflow.com/questions/9737616/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.

Ios Solutions


Solution 1 - Ios

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)
}

Solution 2 - Ios

This is how to hide the first section header in UITableView (grouped style).

Swift 3.0 & Xcode 8.0 Solution

  1. The TableView's delegate should implement the heightForHeaderInSection method

  2. Within the heightForHeaderInSection method, return the least positive number. (not zero!)

     func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
     
         let headerHeight: CGFloat
    
         switch section {
         case 0:
             // hide the header
             headerHeight = CGFloat.leastNonzeroMagnitude
         default:
             headerHeight = 21
         }
     
         return headerHeight
     }
    

Solution 3 - Ios

The answer was very funny for me and my team, and worked like a charm

  • In the Interface Builder, Just move the tableview under another view in the view hierarchy.

REASON:

We observed that this happens only for the First View in the View Hierarchy, if this first view is a UITableView. So, all other similar UITableViews do not have this annoying section, except the first. We Tried moving the UITableView out of the first place in the view hierarchy, and everything was working as expected.

Solution 4 - Ios

Use this trick for grouped type tableView

Copy paste below code for your table view in viewDidLoad method:

tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, tableView.bounds.size.width, 0.01f)];

Solution 5 - Ios

this way is OK.

override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    if section == 0 {
        return CGFloat.min
    }
    return 25
}

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if section == 0 {
        return nil
    }else {
        ...
    }
}

Solution 6 - Ios

I just copied your code and tried. It runs normally (tried in simulator). I attached result view. You want such view, right? Or I misunderstood your problem?

enter image description here

Solution 7 - Ios

Swift3 : heightForHeaderInSection works with 0, you just have to make sure header is set to clipsToBounds.

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
       return 0
}

if you don't set clipsToBounds hidden header will be visible when scrolling.

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    guard let header = view as? UITableViewHeaderFooterView else { return }

    header.clipsToBounds = true
}

Solution 8 - Ios

Update[9/19/17]: Old answer doesn't work for me anymore in iOS 11. Thanks Apple. The following did:

self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
self.tableView.estimatedSectionHeaderHeight = 20.0f;
self.tableView.contentInset = UIEdgeInsetsMake(-18.0, 0.0f, 0.0f, 0.0);

Previous Answer:

As posted in the comments by Chris Ostomo the following worked for me:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return CGFLOAT_MIN; // to get rid of empty section header
}

Solution 9 - Ios

Here is how to get rid of the top section header in a grouped UITableView, in Swift:

tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))

Solution 10 - Ios

Try this if you want to remove all section header completely

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return CGFloat.leastNormalMagnitude
}

Solution 11 - Ios

In Swift 4.2 and many earlier versions, instead of setting the first header's height to 0 like in the other answers, you can just set the other headers to nil. Say you have two sections and only want the second one (i.e., 1) to have a header. That header will have the text Foobar:

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return section == 1 ? "Foobar" : nil
}

Solution 12 - Ios

In iOS 15, this code removes the unwanted section header space.

 if #available(iOS 15.0, *) {
  tableView.sectionHeaderTopPadding = .leastNormalMagnitude
}

Solution 13 - Ios

I can't comment yet but thought I'd add that if you have a UISearchController on your controller with UISearchBar as your tableHeaderView, setting the height of the first section as 0 in heightForHeaderInSection does indeed work.

I use self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height); so that the search bar is hidden by default.

Result is that there is no header for the first section, and scrolling down will show the search bar right above the first row.

Solution 14 - Ios

easiest by far is to return nil, or "" in func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? for a section where you do not wish to display header.

Solution 15 - Ios

Swift Version: Swift 5.1
Mostly, you can set height in tableView delegate like this:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
   return UIView(frame: CGRect(x: 0, y: 0, width: view.width, height: CGFloat.leastNormalMagnitude))
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
   return CGFloat.leastNormalMagnitude
}

Sometimes when you created UITableView with Xib or Storyboard, the answer of up does not work. you can try the second solution:

let headerView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: CGFloat.leastNormalMagnitude))
self.tableView.tableHeaderView = headerView

Hope it works for you!

Solution 16 - Ios

The following worked for me in with iOS 13.6 and Xcode 11.6 with a UITableViewController that was embedded in a UINavigationController:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    nil
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    .zero
}

No other trickery needed. The override keywords aren't needed when not using a UITableViewController (i.e. when just implemented the UITableViewDelegate methods). Of course if the goal was to hide just the first section's header, then this logic could be wrapped in a conditional as such:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if section == 0 {
        return nil
    } else {
        // Return some other view...
    }
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    if section == 0 {
        return .zero
    } else {
        // Return some other height...
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCodoView Question on Stackoverflow
Solution 1 - IosCodoView Answer on Stackoverflow
Solution 2 - Iosuser3378170View Answer on Stackoverflow
Solution 3 - IosGiorgos AthView Answer on Stackoverflow
Solution 4 - IosNitesh BoradView Answer on Stackoverflow
Solution 5 - IosTonnyTaoView Answer on Stackoverflow
Solution 6 - IoscaglarView Answer on Stackoverflow
Solution 7 - Iosh.martinView Answer on Stackoverflow
Solution 8 - IosManindra MoharanaView Answer on Stackoverflow
Solution 9 - IosElijahView Answer on Stackoverflow
Solution 10 - IosAvinashView Answer on Stackoverflow
Solution 11 - IosJaneGoodallView Answer on Stackoverflow
Solution 12 - IosRajeshView Answer on Stackoverflow
Solution 13 - IosRaesuView Answer on Stackoverflow
Solution 14 - IosVilém KurzView Answer on Stackoverflow
Solution 15 - IosmistdonView Answer on Stackoverflow
Solution 16 - IosrlziiiView Answer on Stackoverflow