5

I'm using the UITableView delegate method viewForHeaderInSection to provide a section header in my UITableView.

I initially create a view like this:

UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 50)];

Then add some subviews using Autolayout then return the headerView

The problem I have is I don't want to specifically specify the headerView size. I want to use Autolayout to pin left & right edges to the width of the view. Here's the problem, I have no superview to use in the Autolayout code.

Using the above code, means the header view doesn't autoresize on rotation. You must reload the tableview after rotation.

Any ideas how I can set headerView to pin it's edges to the tableview?

Thanks

Darren
  • 10,182
  • 20
  • 95
  • 162

1 Answers1

2

From my testing, and this answer here, the UIView returned from that method automatically has its origin set to (0, 0), its height set to the value returned from -tableView: heightForHeaderInSection: and its width set to the width of the UITableView.

I was able to add controls to that UIView and even lay them out with auto layout without specifying any particular sizing in the init method.

Here's my code to create the header view:

self.headerView = [[UIView alloc] init];

Here's the code where I lay out the controls inside the header view:

- (void)layoutControls {
    [self.headerView addSubview:self.segmentedControl];
    [self.headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(margin)-[control]-(margin)-|"
                                                                            options:0
                                                                            metrics:@{@"margin":    @(self.segmentedControlLeftRightMargin)}
                                                                              views:@{@"control":   self.segmentedControl}]];
    [self.headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(margin)-[control(==height)]"
                                                                            options:0
                                                                            metrics:@{@"margin":    @(self.segmentedControlTopMargin),
                                                                                      @"height":    @(self.segmentedControlHeight)}
                                                                              views:@{@"control":   self.segmentedControl}]];

    [self.headerView addSubview:self.searchBar];
    [self.headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(margin)-[control]-(margin)-|"
                                                                            options:0
                                                                            metrics:@{@"margin":    @(self.searchBarLeftRightMargin)}
                                                                              views:@{@"control":   self.searchBar}]];
    [self.headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[control1]-(margin1)-[control2]-(margin2)-|"
                                                                            options:0
                                                                            metrics:@{@"margin1":   @(self.segmentedControlBottomMargin),
                                                                                      @"margin2":   @(self.searchBarBottomMargin)}
                                                                              views:@{@"control1":  self.segmentedControl,
                                                                                      @"control2":  self.searchBar}]];

}

Here are the methods for the UITableViewDelgate Protocol:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    // The hard-coded values are accurate for my controls, but you might need more advanced logic
    return 44.0f + self.segmentedControlBottomMargin + 44.0f + self.searchBarBottomMargin;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    return self.headerView;
}
Community
  • 1
  • 1
mbm29414
  • 11,558
  • 6
  • 56
  • 87
  • Thanks, I learnt something, returning a zerorect view uses the correct full size, so no need to use tableview.bounds, however this doesn't correct when rotating. You have to reload the tableview. I'm guessing there's no superview to pin the edges to. – Darren Jan 09 '15 at 21:27
  • Yeah, it appears to be treated "outside of the bounds" of auto layout. When I've needed this behavior in the past, I've actually subclassed `UITableViewCell` and used that instead of section headers. If you actually use sections, it could just be the cell for row 0 (zero). That way, you **DO** get rotation support. – mbm29414 Jan 09 '15 at 21:30
  • That's actually not a bad idea. In fact that would also stop the section header staying on screen when the table scrolls. – Darren Jan 09 '15 at 21:32
  • @Darren That can also be fixed by using a grouped `UITableView`, but I agree that using the `UITableViewCell` subclass is often the better choice. – mbm29414 Jan 09 '15 at 21:41