There are some section in the table that does not contain any data and would like to hide that section.
How to do this?
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.
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 :-)
For hiding a section, even in the middle of the table view you would need all of the following
#define DEBUG_SECTION 1
#if ! DEBUG_BUILD
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section == DEBUG_SECTION)
return CGFLOAT_MIN;
return [super tableView:tableView heightForHeaderInSection:section];
}
//------------------------------------------------------------------------------
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
if (section == DEBUG_SECTION)
return CGFLOAT_MIN;
return [super tableView:tableView heightForFooterInSection:section];
}
//------------------------------------------------------------------------------
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section == DEBUG_SECTION)
return nil;
return [super tableView:tableView titleForHeaderInSection:section];
}
//------------------------------------------------------------------------------
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
if (section == DEBUG_SECTION)
return nil;
return [super tableView:tableView titleForFooterInSection:section];
}
//------------------------------------------------------------------------------
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == DEBUG_SECTION)
return 0;
return [super tableView:tableView numberOfRowsInSection:section];
}
//------------------------------------------------------------------------------
#endif // #if ! DEBUG_BUILD
if you left out titleFor/headerFor... you will get some empty rows
if you left out heightFor... the title/footer header text will still appear
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;
}
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.
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;
}