Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to manually self-size UITableView tableHeaderView/tableFooterView in iOS 11
// For the best results, your tableHeaderView/tableFooterView should be a UITableViewHeaderFooterView with your content inside the contentView.
let tableHeaderView = UITableViewHeaderFooterView()
let fittingSize = CGSize(width: tableView.bounds.width - (tableView.safeAreaInsets.left + tableView.safeAreaInsets.right), height: 0)
let size = tableHeaderView.systemLayoutSizeFitting(fittingSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
tableHeaderView.frame = CGRect(origin: .zero, size: size)
tableView.tableHeaderView = tableHeaderView
// When you set this view to the tableHeaderView/tableFooterView on the table view, the table view will preserve the existing size of its frame.
// If you need to change the size, remove the tableHeaderView/tableFooterView, set a new frame on it, then re-set it on the table view again.
@benpackard

This comment has been minimized.

Copy link

commented May 28, 2019

Should a tableHeaderView really be a subclass of UITableViewHeaderFooterView? The docs say that the UITableViewHeaderFooterView is "a reusable view that you place at the top or bottom of a table section to display additional information for that section." (my bold.) It doesn't mention tableHeaderView or tableFooterView.

@smileyborg

This comment has been minimized.

Copy link
Owner Author

commented May 28, 2019

@benpackard Yep! Especially if you want the contentView automatically inset to the safe area, e.g. on iPhone X in landscape.

@benpackard

This comment has been minimized.

Copy link

commented May 28, 2019

@smileyborg Thanks! Somewhat confusing given the docs and sometimes the mix up between section headers vs table header view, so I appreciate you confirming.

@gorbat-o

This comment has been minimized.

Copy link

commented Jun 14, 2019

Hi, could you explain the context of this piece of code if you have time?

Is it supposed to be called in a viewDidLayoutSubviews for example?

In my case, I am using a container for my headerView and I add the container to the tableheaderView.
It does not seem it will affect what I am doing here :/

For a little bit of context on my side:

// This is a setup function in my viewDidLoad

UIView *headerContainerView = [UIView new];
self.headerView = [CustomView new];

[headerContainerView addSubview:self.headerView];

[self.headerView updateWithTitle:@"Test" andDescription:@"Test description"];
[self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(headerContainerView.mas_top).offset(16);
    make.leading.equalTo(headerContainerView.mas_leading).offset(16);
    make.trailing.equalTo(headerContainerView.mas_trailing).offset(-16);
    make.bottom.equalTo(headerContainerView.mas_bottom).offset(-16);
}];
headerContainerView.transform = self.tableView.transform; // It is legacy code, so the tableview right now is inverted. it should not impact the way we show the tableview.
self.tableView.tableFooterView = headerContainerView;

// The following code was executed before for `tableHeaderView` in the rest of the app, and it was working like a charm. But since I dig a little bit about `tableHeaderViews` apparently set `translatesAutoresizingMaskIntoConstraints ` to `NO` might cause a problem, without even applying any constraints.
//    [headerContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
//        make.centerX.equalTo(self.tableView.mas_centerX);
//        make.width.equalTo(self.tableView.mas_width);
//        make.top.equalTo(self.tableView.mas_top);
//    }];

And then, I have my current ViewController containing this setup that has override viewDidLayoutSubviews:

// It is clearly a workaround for this auto layout issues with tableHeaderView
[super viewDidLayoutSubviews];

if (self.tableView.tableFooterView == nil) {
    return;
}

UIView *tableFooterView = self.tableView.tableFooterView;
CGFloat footerHeight = [tableFooterView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect footerFrame = tableFooterView.frame;

if (footerHeight != footerFrame.size.height) {
    footerFrame.size.height = footerHeight;
    tableFooterView.frame = footerFrame;
    [self.tableView setTableFooterView:tableFooterView];
}

Thank you for your further help and time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.