UITableView : viewForHeaderInSection: not called during reloadData:
IosUitableviewUitableviewsectionheaderIos Problem Overview
I've set up the tableview with correct delegate and datasource linkages.. the reloadData method calls the datasource and the delegate methods except for viewForHeaderInSection:
.
Why is that so?
Ios Solutions
Solution 1 - Ios
The use of tableView:viewForHeaderInSection:
requires that you also implement tableView:heightForHeaderInSection:
. This should return an appropriate non-zero height for the header. Also make sure you do not also implement the tableView:titleForHeaderInSection:
. You should only use one or the other (viewForHeader
or titleForHeader
).
Solution 2 - Ios
The trick is that those two methods belong to different UITableView
protocols: tableView:titleForHeaderInSection:
is a UITableViewDataSource
protocol method, where tableView:viewForHeaderInSection
belongs to UITableViewDelegate
.
That means:
-
If you implement the methods but assign yourself only as the
dataSource
for theUITableView
, yourtableView:viewForHeaderInSection
implementation will be ignored. -
tableView:viewForHeaderInSection
has a higher priority. If you implement both of the methods and assign yourself as both thedataSource
and thedelegate
for theUITableView
, you will return the views for section headers but yourtableView:titleForHeaderInSection:
will be ignored.
I have also tried removing tableView:heightForHeaderInSection:
; it worked fine and didn't seem to affect the procedures above. But the documentation says that it is required for the tableView:viewForHeaderInSection
to work correctly; so to be safe it is wise to implement this, as well.
Solution 3 - Ios
@rmaddy has misstated the rule, twice: in reality, tableView:viewForHeaderInSection:
does not require that you also implement tableView:heightForHeaderInSection:
, and also it is perfectly fine to call both titleForHeader
and viewForHeader
. I will state the rule correctly just for the record:
The rule is simply that viewForHeader
will not be called unless you somehow give the header a height. You can do this in any combination of three ways:
-
Implement
tableView:heightForHeaderInSection:
. -
Set the table's
sectionHeaderHeight
. -
Call
titleForHeader
(this somehow gives the header a default height if it doesn't otherwise have one).
If you do none of those things, you'll have no headers and viewForHeader
won't be called. That's because without a height, the runtime won't know how to resize the view, so it doesn't bother to ask for one.
Solution 4 - Ios
Giving estimatedSectionHeaderHeight
and sectionHeaderHeight
values fixed my problem.
e.g.,
self.tableView.estimatedSectionHeaderHeight = 100 self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension
Solution 5 - Ios
Going off rmaddy 's answer, I was trying to hide the Header view and was returning 0.0f for "tableView:heightForHeaderInSection" and a 0 height View from tableView:viewForHeaderInSection
.
After changing from return 1.0f
to return 0.0f
in tableView:heightForHeaderInSection
, the delegate method tableView:viewForHeaderInSection
was indeed called.
Turns out my desired effect works without having to use "tableView:heightForHeaderInSection"; but this may be useful to others who are having an issue getting "tableView:heightForHeaderInSection" delegate method called.
Solution 6 - Ios
You should implement tableView:heightForHeaderInSection:
and set the height for the header >0.
This delegate method goes along with the viewForHeaderInSection:
method.
I hope this helps.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 40;
}
Solution 7 - Ios
It's worth briefly noting that if your implementation of tableView:heightForHeaderInSection:
returns UITableViewAutomaticDimension
, then tableView:viewForHeaderInSection:
will not be called.
UITableViewAutomaticDimension
assumes that a standard UITableViewHeaderFooterView
will be used that is populated with the delegate method tableView:titleForHeaderInSection:
.
From comments in the UITableView.h
:
> Returning this value from tableView:heightForHeaderInSection:
or tableView:heightForFooterInSection:
results in a height that fits the value returned from tableView:titleForHeaderInSection:
or tableView:titleForFooterInSection:
if the title is not nil.
Solution 8 - Ios
I've just had an issue with headers not showing for iOS 7.1, but working fine with later releases I have tested, explicitly with 8.1 and 8.4.
For the exact same code, 7.1 was not calling any of the section header delegate methods at all, including: tableView:heightForHeaderInSection:
and tableView:viewForHeaderInSection:
.
After experimentation, I found that removing this line from my viewDidLoad
made headers re-appear for 7.1 and did not impact other versions I tested:
// _Removing_ this line _fixed_ headers on 7.1
self.tableView.estimatedSectionHeaderHeight = 80;
… so, there seems to be some kind of conflict there for 7.1, at least.
Solution 9 - Ios
Same issue occured with me but as I was using automatic height calculation from xCode 9, I cannot give any explicit height value as mentioned above. After some experimentation I got solution, we have to override this method as,
-(CGFloat)tableView:(UITableView *)tableView
estimatedHeightForHeaderInSection:(NSInteger)section
{
return 44.0f;
}
Although I have checked both options
- Automatic Height Calculation
- Automatic Estimated Height Calculation
from storyboard as apple says, but still I got this weird error.
Please Note: This Error was shown only on IOS-10 version not on IOS-11 version. Maybe it's a bug from xCode. Thanks
Solution 10 - Ios
The reason why viewForHeaderInSection
does not get called is for one of two reasons:
Either you did not set up your UITableViewDelegate
, or
you set up your UITableViewDelegate
incorrectly.
Solution 11 - Ios
Here's what I've found (Swift 4) (thanks to this comment on another question)
Whether I used titleForHeaderInSection or viewForHeaderInSection - it wasn't that they weren't getting called when the tableview was scrolled and new cells were being loaded, but any font choices I made for the headerView's textLabel were only appearing on what was initially visible on load, and not as the table was scrolled.
The fix was willDisplayHeaderView:
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
if let header = view as? UITableViewHeaderFooterView {
header.textLabel?.font = UIFont(name: yourFont, size: 42)
}
}
Solution 12 - Ios
In my case I have created header view using UITableviewCell
and returning the cell in viewForHeaderInSection
like this
return cell
changed this to
return cell.contentView
Worked for me.
Solution 13 - Ios
In my case
viewForHeaderInSection
was implemented in a derived class far far away that was not bothering to daisy into superclass.
Solution 14 - Ios
In my case it was cause I did not implement:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
Solution 15 - Ios
Sometimes setting tableview.delegate
or datasource = nil
in the viewWillAppear:
or viewDidAppear:
methods can cause this issue. Make sure not to do this...
Solution 16 - Ios
I had cut & paste the following two methods from a Swift 2 project into my Swift 3 project which were never called because in Swift 3 these methods must have "-" before the first parameter name.
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44.0
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: B2BTrolleyHeaderFooterView.reuseIdentifier) as! B2BTrolleyHeaderFooterView
return headerView
}