UITableView : viewForHeaderInSection: not called during reloadData:
Solution 1
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
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
@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
Giving estimatedSectionHeaderHeight
and sectionHeaderHeight
values fixed my problem.
e.g.,
self.tableView.estimatedSectionHeaderHeight = 100
self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension
Solution 5
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.
inforeqd
Updated on July 27, 2020Comments
-
inforeqd almost 4 years
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?
-
rmaddy over 11 yearsMake sure there isn't a typo in the method's signature. One wrong letter will mean it won't be called. Check the case too. Also make sure you are returning 0 from
numberOfSections
. -
inforeqd over 11 yearseverything is correct and compiles correctly.. the issue I wanted to understand is around the timing of when the method is called .. tableView:viewForHeaderInSection is called when the table is just about to be displayed and not as part of the synch execution of [tableview reloadData]
-
rmaddy over 9 yearsFrom the docs for
tableView:viewForHeaderInSection:
: " This method only works correctly whentableView:heightForHeaderInSection:
is also implemented.". -
matt over 9 yearsFine. What the docs say, they say. Now experiment. The facts are as I have stated.
-
rmaddy over 9 yearsAnd how can you have both
titleForHeaderInSection
andviewForHeaderInSection
? The table view will only call one of the two (I forget which gets precedence at the moment). -
matt over 9 yearsActually there is one more piece of the puzzle, which is that sometimes
viewForHeader
is called without any of those three ways of assigning a height. I have had this happen, where myviewForHeader
was called and headers showed up just fine, until one day, with no change on my part, they didn't. That's when I started experimenting to discover what the minimal requirements are forviewForHeader
to be called. And now I know. And now so do you. -
matt over 9 yearsIf both
titleForHeaderInSection
andviewForHeaderInSection
are implemented, and assumingviewForHeaderInSection
returns a UITableViewHeaderFooterView, they will both be called, and in fact this is a perfectly reasonable thing to do. -
testing over 9 yearsNow I tried to implement
titleForHeaderInSection
together withviewForHeaderInSection
(whereas I only need the view). It works as matt stated but what shouldtitleForHeaderInSection
return? It only worked for me when returning an empty space. So it's still a compromise because I have to additionaly return things (height or space). -
casillas over 8 years@matt, do you have any clue for the following stackoverflow.com/questions/34665313/…
-
matt over 8 years@texas No, I don't do xamarin. Adding another level of indirection on top of the Cocoa frameworks would just make my head explode. :)
-
casillas over 8 years:-) Just ignore about xamarin, my question is simply that my implementation always calls
TitleHeader
but not callingViewHeight
andViewHeader
. What might be reason? -
GreatWiz over 8 yearsif you set
estimatedSectionHeaderHeight
to some value,tableView:viewForHeaderInSection
will be called (similarly to how auto dimensions for rows works) -
Benjohn over 8 yearsInteresting, thanks. Back at 7.1 this subtlety of estimated height was important for cells, so might have been the case for headers too – but it's not terribly relevant now!
-
denis631 about 8 yearsYou made my day!!! Forgot to assign
UITableViewDelegate
toself
, because I thought, thattableView:viewForHeaderInSection
is aUITableViewDataSource
method. Thank you! -
Happiehappie over 7 years@maddy OMG Thank you, it's so stupid of me i created my instances but I didn't append to my array
-
romrom over 7 yearsYou can absolutely have both. viewForHeaderInSection: will have precedence over titleForHeaderInSection: The only requirement is that you set estimatedSectionHeaderHeight on your table view with something different than 0, otherwise viewForHeaderInSection: will never get called
-
zevij about 7 yearsMy issue started after upgrading to Swift 3.1. This solution fixed it.
-
Karlis about 7 yearsHave you tested that your answer actually works? Becaus eif you read carefully then it's stated that initially the viewForHeaderInSection is called. It's not called only when the table is reloaded!
-
mfaani over 6 yearsAny reason you excluded
estimatedSectionHeaderHeight
from your three ways? -
mfaani over 6 years"tableView:viewForHeaderInSection" is not vital. What's vital is you somehow return a height. You could achieve that through either 1. estimate or 2. a hardcoded value or 3. a
titleForHeader
which has an intrinsic size. The intrinsic size is calculated based on the Font Family and size. -
matt over 6 years@Honey Look at the date on that answer.
-
mfaani over 6 yearsOuch/hah. Didn't know. You have look at the date I started developing :) but I guess adding that to the answer won't bother.
-
Sharukh Mastan over 6 years@pbuchheit Apple Docs says it is available from iOS 7.0+, please have a look here, developer.apple.com/documentation/uikit/uitableview/…
-
pbuchheit over 6 years@Sharukh Mastan Looks like you are correct. For some reason I was getting a warning when I tried using that property, but it went away after doing a clean build.
-
Ortwin Gentz over 6 yearsAdding to @romrom's comment: if you have implemented both
titleForHeaderInSection:
andviewForHeaderInSection:
and the view returned from the latter is a subclass ofUITableViewHeaderFooterView
then itstextLabel.text
is automatically set to the all-caps version of thetitleForHeaderInSection:
string. To prevent this behavior, either don't implementtitleForHeaderInSection:
or use a custom label instead of the inheritedtextLabel
. -
Victor Engel almost 3 yearsI've just encountered a situation where only one of the headers isn't called. The heightForHeaderInSection is called for all sections, but the viewForHeaderInSection is not called for one of the sections. Which one? The one where the included textfield was just edited. Why does it need to be called? Because the editing could cause the section sort to change. When the data is updated, it is sorted, so I want to redisplay ALL sections, including the section just edited. Weirdly, that is the one that is skipped even though height is queried.