7

I did not find an equivalent question on stackoverflow, so I'll post my own question on that problem (please tell me if something is not understandable):

Problem:

I use a common indexed tableView with section headers from A-Z (like in the contacts.app) in a custom UITableViewController. I override tableView:viewForHeaderInSection: to provide my own section-header views.

When the user scrolls the table up or down, I need to listen to the section headers that appear/disappear at the top or bottom of the tableView (to change some custom view accordingly).

I override these methods (available since iOS 6.0) that do exactly what I need:

  1. tableView:didEndDisplayingHeaderView:forSection:

  2. tableView:willDisplayHeaderView:forSection:

2. is never getting called when scrolling up/down the tableView, whereas method 1 is getting called every time a section header disappears from screen.

I have no idea why the one is getting called and the other is not. Is this a bug from apple or what do I do wrong?


Similar Question:

I've found a similar question here How to call a method “willDisplayFooterView” during Table View cusomization? Where one answer was like:

They will only be called under iOS 6.0 or later and only if you also implement the other header/footer title/view methods. If you are providing a header or footer, there is no need for these to be called

I'm not sure if I understand that answer right, but if so, it seems to be important which methods are implemented in the subclass.


Code:

I post only the non-empty overridden delegate and data-source methods of my tableViewController:

tvcA.m

@implementation tvcA 
...
#pragma mark - Table view data source 

- (NSArray *) sectionIndexTitlesForTableView : (UITableView *) tableView 
{
    // returns sectionIndexArray with alphabet for example
}

- (UIView *) tableView : (UITableView *) tableView
viewForHeaderInSection : (NSInteger) section 
{
    MNSectionHeaderView* headerView = [[MNSectionHeaderView alloc] initWithFrame : CGRectMake(0, 0, 260, 22)];
    return headerView;
}

-     (NSInteger) tableView : (UITableView *) tableView
sectionForSectionIndexTitle : (NSString *) title
                    atIndex : (NSInteger) index {...}
...
@end

tvcB.h (inherits from tvcA)

@interface tvcB : tvcA
...
@end

tvcB.m

@implementation tvcB
...
#pragma mark - Table view data source

- (NSInteger) numberOfSectionsInTableView : (UITableView *) tableView {...}

- (NSInteger) tableView : (UITableView *) tableView
  numberOfRowsInSection : (NSInteger) section {...}

- (UITableViewCell*) tableView : (UITableView *) tableView
      cellForRowAtIndexPath : (NSIndexPath *) indexPath {...}

- (CGFloat) tableView : (UITableView *) tableView
heightForHeaderInSection : (NSInteger) section {...}

- (UIView *) tableView : (UITableView *) tableView
viewForHeaderInSection : (NSInteger) section {....}


#pragma mark - Table view delegate

-    (void) tableView : (UITableView*) tableView
willDisplayHeaderView : (UIView*) view
       forSection : (NSInteger) section { 
    // custom configurations
}

-         (void) tableView : (UITableView*) tableView
didEndDisplayingHeaderView : (UIView*) view
                forSection : (NSInteger) section {
   // custom configurations    
}

- (void) tableView : (UITableView *) tableView
didSelectRowAtIndexPath : (NSIndexPath *) indexPath {...}
...
@end
Community
  • 1
  • 1
anneblue
  • 706
  • 4
  • 21

2 Answers2

10

I think I got it now.

The Similar Question mentioned above just already gives the answer, which I didn't get right:

[...] If you are providing a header or footer, there is no need for these to be called

(With "these" he might have meant the two methods I override above.)

As I do provide own section headers, instead of the method tableView:willDisplayHeaderView:forSection:, the other overriding method: tableView:viewForHeaderInSection: is getting called each time a section header enters the screen.

So finally I will just do my needed configurations in the last mentioned method.

Community
  • 1
  • 1
anneblue
  • 706
  • 4
  • 21
0

For some reason in my case tableView:viewForHeaderInSection: was getting called for all sections of all my tables (I have a scrollView with lots of tables). So your solution wasn't working for me. However, since I only needed to know which is the first visible section when the VC is popped, I came up with this nice solution:

    NSInteger firstVisibleSection = 0;
    for (int i = 0; i < [_board.swimlanes count]; i++)
    {
        CGRect sectionRect = [currentTable rectForSection:i];
        BOOL containsPoint = CGRectContainsPoint(sectionRect, currentTable.contentOffset);
        if (containsPoint)
        {
            firstVisibleSection = i;
            break;
        }
    }

Might be helpful for someone with the same problem :)

AXE
  • 8,335
  • 6
  • 25
  • 32
  • I assume, you only wanted to track the topmost section that is visible on screen, right? Of course: `tableView:viewForHeaderInSection:` is getting called EVERY time a section header (re-)appears on screen - on top AND/OR on bottom. A much easier way to track the top section is: add a class property like `NSUInteger topSection` and set it in `tableView:viewForHeaderInSection:` like: `if(section < _topSection){ _topSection = section;}` and in `tableView:didEndDisplayingHeaderView:forSection:nextSectionShown:` `if(section == _topSection) {_topSection = nextSection;}`. Try it out- it's much easier – anneblue Mar 31 '14 at 10:41
  • I tried - it doesn't work. At least in my case. I have a paged scrollView with a table in every page. When the view first appears `tableView:viewForHeaderInSection:` gets called for ALL headerView's, not just the ones that are on the screen. Also, with your suggested solution you track the section all the time while with the one I posted above you just check when you need it. – AXE Mar 31 '14 at 10:56
  • 1
    OK, I think, both solutions (checking when you need it/tracking all the times) might be helpful in different situations though (in my case, I needed that information being updated all the time). Just because I'm curious: isn't it always the first section(s) `0` shown on top when your paged scrollView/tables are loaded the first time? And - by the way: did you know you can check for which tableView the method `tableView:viewForHeaderInSection:` is getting called like: `if (tableView == self.searchDisplayController.searchResultsTableView)...`? – anneblue Mar 31 '14 at 11:35
  • Nope, when the VC loads I focus on the last viewed swimlane on previous session. That's what I need the info for ;) And that's why I need it only at the end. I don't say my solution is the only one but it turned out to be the perfect one for me so that's why I'm offering it here. – AXE Mar 31 '14 at 14:50