31

There are some section in the table that does not contain any data and would like to hide that section.

How to do this?

Teo Choong Ping
  • 12,512
  • 18
  • 64
  • 91

11 Answers11

62

Actually, you can "hide" a section. If you want to use a similar behaviour to the built-in contacts app, where sections are hidden but still listed in the index on the right you can do the following:

Implement the UITableViewDataSource protocol:

  • Return all section names (even hidden ones) in - the sectionIndexTitlesForTableView method.

  • For each empty section, return nil from the titleForHeaderInSection method.

  • For each empty section return 0 for the numberOfRowsInSection method.

I find this works better than deleting sections, because the user has consistent index navigation.

TJez
  • 1,969
  • 2
  • 19
  • 24
21

You can't "hide" a section as such, but you can "delete" it from the table view using the deleteSections:withRowAnimation: method. This will remove it from the view, with an optional animation, without affecting your backing data. (You should, however, update the data anyway so that the section doesn't reappear.)

More info: UITableView class reference

Tim
  • 59,527
  • 19
  • 156
  • 165
  • 1
    I've used this: `[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:nil];` but I receive this message: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (3) must be equal to the number of sections contained in the table view before the update (3), plus or minus the number of sections inserted or deleted (0 inserted, 1 deleted).' Any idea? – Claus Feb 19 '13 at 16:24
  • 1
    @Claus: this answer is pretty old. You might consider [asking a new question](http://stackoverflow.com/questions/ask). Briefly, though, it looks like you need to update the value you're returning from your `-numberOfSectionsInTableView:` data source method. The error is indicating that you start with three sections, delete one, then claim that you still have three sections left. – Tim Feb 19 '13 at 19:16
  • 1
    thanks! I found an easier way setting the number of row for section to 0 and removing the section header view. – Claus Feb 20 '13 at 15:39
  • @Claus How do it ? – zhaoyou Nov 14 '16 at 08:26
14

It is true that 0 is not a valid height for headers and footers. However, the heights are CGFloat values. You can specify a very small number (I've used 0.1) for the height of the section headers and footers.

Kind of a hack, but it works.

marcus
  • 141
  • 2
  • 2
5

I disagree with Tim. We have a way to access any section/row of a table from anywhere in our code and change its .hidden property (and all other properties).

This is the way I usually use:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:2];
[self.SeymourCakesTableView cellForRowAtIndexPath:indexPath].hidden = YES;
Pang
  • 9,564
  • 146
  • 81
  • 122
Deepukjayan
  • 3,525
  • 1
  • 20
  • 31
  • 2
    It works, but the problem is that the cells below it do not move up. In my case the cells are at the bottom table, and the solution is good. – Dr.Luiji Nov 07 '12 at 11:00
  • I didn't notice such an issue. I will have a look once I get time. Thanks for pointing out the issue. – Deepukjayan Nov 09 '12 at 05:05
2

You can set the number of rows in that section to 0. However, it will leave a noticeable blank area where it used to be.

Cocoanut
  • 664
  • 1
  • 5
  • 7
2

You can also return the number of records that do contain data from the numberofSectionsInTableView: method and use a switch(indexPath.section) where you let the empty records 'fall through' to the next switch, like:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    switch (indexPath.section) {
        case 0:
            return <header cell>;
            break;

        case 1:
            if(firstRecordHasData){
                return <second cell>;
                break;
            }

        case 2:
            if(secondRecordHasData){
                return <second cell>;
                break;
            }

        case 3:
            return <some other cell>;
            break;

        default:
            return <a regular cell>;
            break;
    }   
}

I was struggling with this for a while because I had to leave out sections in the middle of a grouped table. Tried with setting cell-, header- and footer heights to 0.0 but that didn't work. Couldn't just delete certain sections because of the called methods depending on the selected row. This was going to be a huge if..else if...else if with multiple callings of subroutines. Glad I thought of the good old switch method, maybe it helps you as well :-)

Maarten Wolzak
  • 2,651
  • 1
  • 19
  • 18
  • 1
    What happens if the first record has no data, and the second record does? Section==1 would fall through Case 1 and return the Case 2 Cell. But Section==2 would not know that Case 1 fell through and would also return the Case 2 Cell, when you want it to return the Case 3 Cell. – jamesmoschou Oct 04 '11 at 05:50
1

You probably need to remove the section itself from the data backing your table. I don't think there's anything that lets you just hide a section.

Simon
  • 1,746
  • 1
  • 13
  • 21
1

You can set the particular section rows height to 0. Also, with the section header if you want. Datasource would still be there, only not showing up.

Section Rows

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0) {
        if (_shouldHidden) {
            return 0.0;
        }
        else {
            return 55.0;
        }
    }
    else {
        return 55.0;
    }
}
ariauakbar
  • 103
  • 9
  • what if section has header and footer ? will we override another 4 method to hide it ? too much unnecessary work, but still there is no proper way to achieve that mucking solution.. – ACAkgul Nov 14 '18 at 07:40
1

If you return 0 for the height of the section, Apple API will ignore it. So just return a small value greater than 0.

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

  return 44;
}

Also implement view for header and return nil for the section you don't want to show.

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
  if (section == 0 && !self.personaCells.count) {
    return nil;
  }

  UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 44)];
  UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(15, 20, headerView.frame.size.width, 20)];
  NSString *headerTitle = @"SAMPLE TITLE";
  headerLabel.text = headerTitle;    
  [headerView addSubview:headerLabel];
  return headerView;
}
Raul Lopez
  • 751
  • 5
  • 7
0

Try like this:-

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    CGFloat headerHeight=10.f;
    if (section==0)
    {
        headerHeight=0.01f;
    }
    else
    {
        headerHeight=50.0f;
    }
    return headerHeight;
}
Hussain Shabbir
  • 14,801
  • 5
  • 40
  • 56
0

For the case of static table, that is, the table sections and cells are configured in Storyboard. The following are my strategies to hide a specified section depending conditions.

Step one: implement two func defined in UITableViewDelegate - heightForRowAt - heightForHeaderInSection

For example, here are swift codes:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
{
   // if indexPath contains the specified section AND
   //    the condition for hiding this section is `true`
   //       return CGFloat(0)
   // else 
   //    return super.tableView(tableView, heightForRowAt: indexPath)
}

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat 
{
   // similar logic to set header height
}

Step two: define a func to set cells hidden for specific section and call it from viewWillAppear:

private func setSectionVisible()
{
   /*
   if condition for visible is true
      let index = IndexPath(row:..., section:...)
      let cell = self.tableView.cellForRow(at: index)
      cell.isHiden = true
   */
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.setSectionVisible()
}

In case you need to reload tableview, you may need to call setSectionVisible() again.

I think this strategy may work for dynamic data from DataSource. In this way, you can control when to make specific section visible or hidden.

David.Chu.ca
  • 37,408
  • 63
  • 148
  • 190