I have a table view with a table header view created through interface builder inside the same xib. I want to set the height of the header based on the screen size, for example 50% of the screen height.
Here is what I get with a static height on an iPhone 4s:
And here is is what I get on an iPhone 6:
Note that the content of the header is static.
I cannot set constraints to the header using auto layout. I tried to set a height constraint based on the height of the table view but it does not seem to be possible in interface builder. Control-dragging does not work. I cannot drag a line from the header to the table view or even to the header itself.
How can I set the header's height based on the screen size?
Unfortunately, table header views cannot be sized using auto layout. You can use auto layout for elements inside the header but you have to specify the header's size by explicitly setting its frame. If the header's height is static and known at compile time you can use IB. However, if the height is dynamic or depends on the device (as in your case), you have to set it in code.
A quite flexible solution would be to create a custom subclass of UITableView
and adapt the header's frame in the layoutSubviews
method. This way the header's size gets automatically adjusted when the table view is resized. You have to be careful, however, to only re-apply the header's frame when a change is actually needed to avoid an infinite loop.
Here's what it would look like in Objective-C:
@interface MyTableView : UITableView
@end
@implementation MyTableView : UITableView
- (void)layoutSubviews {
[super layoutSubviews];
if (self.tableHeaderView) {
UIView *header = self.tableHeaderView;
CGRect rect = CGRectMake(0, 0, self.bounds.size.width,
self.bounds.size.height / 2);
// Only adjust frame if needed to avoid infinite loop
if (!CGRectEqualToRect(self.tableHeaderView.frame, rect)) {
header.frame = rect;
// This will apply the new header size and trigger another
// call of layoutSubviews
self.tableHeaderView = header;
}
}
}
@end
The Swift version looks like this:
class MyTableView: UITableView {
override func layoutSubviews() {
super.layoutSubviews()
if let header = tableHeaderView {
let rect = CGRectMake(0, 0, bounds.size.width, bounds.size.height / 2)
// Only adjust frame if needed to avoid infinite loop
if !CGRectEqualToRect(header.frame, rect) {
header.frame = rect
// This will apply the new header size and trigger
// another call of layoutSubviews
tableHeaderView = header
}
}
}
}
Note that the above snippets use the bounds of the table view rather than the screen size to calculate the header size.
Update: Note that sometimes an additional call to layoutIfNeeded
is needed after setting the tableHeaderView
property. I ran into an issue where section headers were drawn above the header view without calling layoutIfNeeded
.
I have tried the following code and it seems to work on iOS7 and iOS8. It changes the height of the header frame to half the screen height. You might want to subtract the height of the navigation and status bar from the screen height before /2, if the header has to be half the size of the table view area only.
- (void)viewDidLoad
{
[super viewDidLoad];
// Your other code
// Set the table header height
CGRect headerFrame = self.tableView.tableHeaderView.frame;
headerFrame.size.height = [[UIScreen mainScreen] bounds].size.height/2;
self.tableView.tableHeaderView.frame=headerFrame;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With