UITableView : viewForHeaderInSection: not called during reloadData:

62,090

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 the UITableView, your tableView:viewForHeaderInSection implementation will be ignored.

  • tableView:viewForHeaderInSection has a higher priority. If you implement both of the methods and assign yourself as both the dataSource and the delegate for the UITableView, you will return the views for section headers but your tableView: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.

Share:
62,090
inforeqd
Author by

inforeqd

Updated on July 27, 2020

Comments

  • inforeqd
    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
    rmaddy over 11 years
    Make 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
    inforeqd over 11 years
    everything 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
    rmaddy over 9 years
    From the docs for tableView:viewForHeaderInSection:: " This method only works correctly when tableView:heightForHeaderInSection: is also implemented.".
  • matt
    matt over 9 years
    Fine. What the docs say, they say. Now experiment. The facts are as I have stated.
  • rmaddy
    rmaddy over 9 years
    And how can you have both titleForHeaderInSection and viewForHeaderInSection? The table view will only call one of the two (I forget which gets precedence at the moment).
  • matt
    matt over 9 years
    Actually 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 my viewForHeader 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 for viewForHeader to be called. And now I know. And now so do you.
  • matt
    matt over 9 years
    If both titleForHeaderInSection and viewForHeaderInSection are implemented, and assuming viewForHeaderInSection returns a UITableViewHeaderFooterView, they will both be called, and in fact this is a perfectly reasonable thing to do.
  • testing
    testing over 9 years
    Now I tried to implement titleForHeaderInSection together with viewForHeaderInSection (whereas I only need the view). It works as matt stated but what should titleForHeaderInSection 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
    casillas over 8 years
    @matt, do you have any clue for the following stackoverflow.com/questions/34665313/…
  • matt
    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
    casillas over 8 years
    :-) Just ignore about xamarin, my question is simply that my implementation always calls TitleHeader but not calling ViewHeight and ViewHeader. What might be reason?
  • GreatWiz
    GreatWiz over 8 years
    if you set estimatedSectionHeaderHeightto some value, tableView:viewForHeaderInSection will be called (similarly to how auto dimensions for rows works)
  • Benjohn
    Benjohn over 8 years
    Interesting, 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
    denis631 about 8 years
    You made my day!!! Forgot to assign UITableViewDelegate to self, because I thought, that tableView:viewForHeaderInSection is a UITableViewDataSource method. Thank you!
  • Happiehappie
    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
    romrom over 7 years
    You 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
    zevij about 7 years
    My issue started after upgrading to Swift 3.1. This solution fixed it.
  • Karlis
    Karlis about 7 years
    Have 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
    mfaani over 6 years
    Any reason you excluded estimatedSectionHeaderHeight from your three ways?
  • mfaani
    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
    matt over 6 years
    @Honey Look at the date on that answer.
  • mfaani
    mfaani over 6 years
    Ouch/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
    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
    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
    Ortwin Gentz over 6 years
    Adding to @romrom's comment: if you have implemented both titleForHeaderInSection: and viewForHeaderInSection: and the view returned from the latter is a subclass of UITableViewHeaderFooterView then its textLabel.text is automatically set to the all-caps version of the titleForHeaderInSection: string. To prevent this behavior, either don't implement titleForHeaderInSection: or use a custom label instead of the inherited textLabel.
  • Victor Engel
    Victor Engel almost 3 years
    I'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.