theDuncs
theDuncs

Reputation: 4843

UITableView section header disappears if I insert or delete rows

I have a UITableView with 4 sections. Three of these sections have a header view.

The header view is a UITableViewCell, which I am de-queueing as a normal cell in the viewForHeaderInSection: delegate.

If I insert or delete a row from any section, the other tableview header cells disappear.

I'm assuming this has something to do with cell reuse, however the cells initially all appear on screen (all three headers appear onscreen at the same time).

I've tried reloading the other sections after the insert or delete, but that doesn't help.

Here's some code:

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    switch (section) {

        case kSectionCardInformation:
        case kSectionContactInformation:
        case kSectionTags: {

            static NSString *CellIdentifier = @"EditContactHeaderCell";
            EditContactHeaderCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
            return cell;
        }

        default:
            return nil;
    }
}

And here is where I delete the row in the revelant section:

- (void)deleteTag:(CDTag *)tag {

    [self.tableView beginUpdates];

    NSMutableArray *objects = [self.sections objectAtIndex:kSectionTags];
    if ([objects containsObject:tag]) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[objects indexOfObject:tag] inSection:kSectionTags];
        [objects removeObject:tag];

        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationMiddle];

        [self.contact deleteTag:tag];
    }

    [self.tableView endUpdates];
}

Any help, greatly appreciated.

Upvotes: 32

Views: 9468

Answers (7)

Diaa SAlAm
Diaa SAlAm

Reputation: 386

Do not return your FooterCell or HeaderCell , or your reusable identifier. Return the reuseIdentifier.contentView. For me it's:

return headerCell!.contentView.

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let headerCell = tableView.dequeueReusableHeaderFooterView(withIdentifier:"CustomViewHeaderView") as! CustomViewHeaderView

    return headerCell.contentView
}

Upvotes: 2

Alejandro Vargas
Alejandro Vargas

Reputation: 1384

For Swift 4,5

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

    let containerView = UIView()
    guard let headerCell = tableView.dequeueReusableCell(withIdentifier: "MyHeaderView") as? MyHeaderView else { fatalError(" Failed to load MyHeaderView") }
    containerView.addSubview(headerCell)
    return containerView
}

Upvotes: 6

dsunku
dsunku

Reputation: 513

Returning the contentView of the cell worked nicely for me. No need to wrap the cell in a UIView.

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let headerCell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell")
    return cell.contentView
}

Upvotes: 20

Anwaar Malik
Anwaar Malik

Reputation: 141

Correct way to resolve this problem is to use UITableViewHeaderFooterView instead of using UITableViewCell for header section. Like @Francois Nadeau answered.

For more detail on how to use UITableViewHeaderFooterView for header section please see this answer: https://stackoverflow.com/a/36931047

Upvotes: 2

Francois Nadeau
Francois Nadeau

Reputation: 7463

Adding comment since I had the same problem... The problem was that I too was using a UITableViewCell as a header instead of using an UITableViewHeaderFooterView.

To fix the problem:

  1. Create a nib file and make your custom header there instead of within the UITableView on your storyboard.
  2. Link it to your custom UITableViewHeaderFooterView class
  3. Register this nib inside your viewDidLoad function

    override func viewDidLoad() {
        self.tableView.rowHeight = UITableViewAutomaticDimension
    
        self.tableView.register(UINib(nibName: "NibFileName", bundle: nil), forHeaderFooterViewReuseIdentifier: "CustomViewHeaderView")
    }
    
  4. Dequeue your reusable HeaderFooterView from the viewForHeaderInSection function:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let cell = tableView.dequeueReusableHeaderFooterView(withIdentifier:"CustomViewHeaderView") as! CustomViewHeaderView
    
        return cell
    }
    

This fixed my disappearing Header. I hope it can help others.

Upvotes: 18

I dont know why are you are using tableview cell for header, but my assumption is that

You have missed the break statement

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    switch (section) {

        case kSectionCardInformation:
            break;
        case kSectionContactInformation:
            break;
        case kSectionTags: {

            static NSString *CellIdentifier = @"EditContactHeaderCell";
            EditContactHeaderCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
            return cell;
        }

        default:
            return nil;
    }
}

Check nil condition before returning the cell, if it was nil then create the cell.

            static NSString *CellIdentifier = @"EditContactHeaderCell";
            EditContactHeaderCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

            return cell ?: createdCellNewly;

Updates:

Then check your numberOfSectionsInTableView:(UITableView *)tableView method returns the proper count.

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
         // returning count is correct?
    }

Check and set the tableview's delegate & datasource.

Upvotes: -1

louissmr
louissmr

Reputation: 748

Just wrap your UITableViewCell into a UIView.

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

switch (section) {

    case kSectionCardInformation:
    case kSectionContactInformation:
    case kSectionTags: {

        static NSString *CellIdentifier = @"EditContactHeaderCell";
        EditContactHeaderCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        UIView * view = [[[UIView alloc] init] autorelease];
        [view addSubview:cell];
        //setup the view's frame: fixed, autolayout, ...
        return view;
    }

    default:
        return nil;
}

}

Upvotes: 25

Related Questions