43

I want to create a custom header section view in a separate .xib using IB

However in IB i cannot find a component UITableViewHeaderFooterView (similar to UITableViewCell) and assign a reuse for it

So how to create in custom header section?

I create a class MySection which inherits from UITableViewHeaderFooterView Create a .xib, MySection.xib Register xib for cell reuse

the problem is, how to use the initWitReuseIdentifier....

Peter Lapisu
  • 19,915
  • 16
  • 123
  • 179

9 Answers9

70

It's absolutely possible and Apple provides an example here.

Download the sample code and look at the SectionHeaderView.xib.

The way to do it is to create a xib with a single UIView on it. Then, set the class type to a class that inherits from UITableViewHeaderFooterView.

Once you have a nib with a class that inherits from UITableViewHeaderFooterView, call the following to register the class for reuse as a header or footer:

static NSString * const SectionHeaderViewIdentifier = @"SectionHeaderViewIdentifier";

[self.tableView registerNib:[UINib nibWithNibName:@"SectionHeaderView" bundle:nil] forHeaderFooterViewReuseIdentifier:SectionHeaderViewIdentifier];

To put the view into use, implement the table delegate method tableView:viewForHeaderInSection: like so:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSinteger)section {

    SectionHeaderViewClass *sectionHeaderView = (SectionHeaderView *)[tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionHeaderViewIdentifier];

    // Do stuff...

    return sectionHeaderView;
}
Jagat Dave
  • 1,643
  • 3
  • 23
  • 30
Matt Becker
  • 2,338
  • 1
  • 28
  • 36
  • 26
    On iOS8 there will be a warning like this: Setting the background color on UITableViewHeaderFooterView has been deprecated. Please use contentView.backgroundColor instead. To fix, in IB, set the background color of the UIView to "Default". – Farhad Malekpour Apr 04 '15 at 04:19
  • 3
    In iOS 8.3, You need to also set the UITableView's sectionHeaderHeight property to something, otherwise it defaults to 0 and your delegate method won't be called. (Yeah, this is dumb.) – patr1ck Jul 08 '15 at 04:19
  • 1
    Clarifying the OP (because it took me a while): Your XIB should have *one* root-level subview (analogous to a `UITableViewCell`'s content view) and all your other views should be subviews of it. Also in addition to @patr1ck's comment above, it seems in iOS 10.x you must set both `tableView.sectionHeaderHeight` *and* `tableView.estimatedSectionHeaderHeight` (even if you override the values for individual sections in your `UITableViewDelegate`.) – Robert Atkins Dec 29 '16 at 09:59
  • 4
    The problem with this is that your subviews of the header/footer view will not end up as subviews of the contentView, where they should be -- instead they will be added directly to the UITableViewHeaderFooterView itself. – smileyborg Aug 10 '17 at 21:02
  • 6
    @smileyborg Is there a way at all to add the subviews to the `contentView` of a `UITableViewHeaderFooterView` via Interface Builder? – Apoorv Khatreja Oct 02 '18 at 17:30
21

I have written a guide (tested on iOS 9), which comprise of 4 steps:

  1. Subclass UITableViewHeaderFooterView
  2. Create Nib with the subclass view, and add 1 container view which contains all other views in the header/footer
  3. In viewDidLoad, call registerNib:forHeaderFooterViewReuseIdentifier: for the table view
  4. Implement viewForHeaderInSection and use dequeueReusableHeaderFooterViewWithIdentifier to get back the header/footer
samwize
  • 25,675
  • 15
  • 141
  • 186
  • 1
    I wonder why this doesn't work with Views in Interface Builder. It doesn't instantiate my UILabel on the view. I tried nesting it in a container view. They are all contained in a custom UITableViewHeaderFooterView subclass. – Andrew Kirna Jul 15 '19 at 19:12
  • how to give button action in that UITableViewHeaderFooterView?? – Ramakrishna Oct 30 '19 at 10:39
  • @AndrewKirna Contents on footer view not visible or loading. Only empty grey bar is shown not even background color getting changed. Not getting what is wrong. – iPhone 7 Feb 02 '20 at 11:19
  • Hi @iPhone7. I only decided to respond because I still have an iPhone 7...jk but that is my phone I commented above because I didn't get it to work either. Since then, I've been designing all of my custom `UITableViewHeaderFooterView`s in Swift. Then I register the classes with the table and apply them with `dequeueReusableHeaderFooterView(withIdentifier:)`. Hope that helps! – Andrew Kirna Feb 06 '20 at 04:49
5

While all these answers work, they don't quite address the original question of how to set the reuseIdentifier using Interface Builder. It is, indeed, possible with the help of "User Defined Runtime Attributes". You can set the reuseIdentifier directly in Interface Builder using an attribute:

Interface Builder user-defined runtime attributes

Doing this will accomplish exactly the same thing as the native reuseIdentifier field in UITableViewCell Interface Builder attribute inspector.

dbart
  • 5,468
  • 2
  • 23
  • 19
  • Seems like it's a bug. because technically there should be a field to add identifier as you are able to dequeue `Header View` in `Table View`. – Alizain Prasla Aug 03 '21 at 12:17
3

Following workarounds enable me to drag-assign IB items to code as variables. UITableViewHeaderFooterView doesnt allow that out of the box.

  1. create a (New File/CocoaTouchClass) UITableViewHeaderFooterView .h.m.xib normally

  2. temporarily rename superclass from UITableViewHeaderFooterView to UIView. Drag-assign your UI items to code as needed, IB will assign key-value correctly, revert back to UITableViewHeaderFooterView when done.

  3. in your tableview, use registerNib: to register instead of registerClass:. prepare the rest of tableview normally (ie:dequeue).
dklt
  • 1,703
  • 1
  • 12
  • 12
1

As of iOS 8, subviews of UITableHeaderFooterView should be in a container view and you should not set background on header/footer views. Object Library lacks UITableHeaderFooterView, so I tried the approach of creating an UIView in xib and adding another one into it as Container View. My concern was that there's not content view outlet on UITableHeaderFooterView and I cannot be sure that my content view actually ends up as content view.

This sounds like a hack or API missuse, however I experienced no warnings or problems with this approach:

  1. Create a subclass of UITableHeaderFooterView
  2. Create an empty xib for it
  3. Drag an UITableViewCell from object library
  4. Assign the class of your UITableHeaderFooterView to that cell
  5. Assign the reuse identifier

I would like to know about any (potential) problems with this approach, please comment.

eagle.dan.1349
  • 611
  • 1
  • 8
  • 20
0

Its enough to create a view and assign its class in IB (the reuse identifier doesn't need to be set in interface builder (as by a custom UITableViewCell))

Peter Lapisu
  • 19,915
  • 16
  • 123
  • 179
-1

UITableViewHeaderFooterView documentation contains registerNib:forHeaderFooterViewReuseIdentifier: method

But currently (as of Sep 4 '13) Object Library in Interface Builder didn't include a UITableViewHeaderFooterView. This makes registerNib:forHeaderFooterViewReuseIdentifier: useless, because there’s no way to configure the view correctly in the nib. Perhaps it is better to try reusing cell ...

Leszek Zarna
  • 3,253
  • 26
  • 26
-1
  1. create new view in xib

  2. Load view from nib and set to view as footerview to tableview

UIView *headerview = [[[NSBundle mainBundle] loadNibNamed:@"ReguistrationHeaderView" owner:self options:nil] firstObject]; [self.tableview setTableFooterView:headerview];

Kishor
  • 376
  • 4
  • 14
-2

I always used UITableViewCell as Headers (or Footers) for my tables to be able to edit them directly in the storyboard.

My workflow :

  • I create a MyHeaderTableViewCell class subclassing UITableViewCell and adding all the outlets I need
  • I add a UITableViewCell to my table in my storyboard
  • I give it a reuse identifier (es: "HeaderCell")
  • I dequeue the cell and use its content as my header

The crucial part is returning the contentView of the headerCell (not the headerCell itself) otherwise you'll run into strange behaviors when playing with reloadRowsAt or similar functions (disappearing headers at most).

This is my code :

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let headerCell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell") as! MyHeaderTableViewCell

    headerCell.lblTitle.text = "My Title"

    return headerCell.contentView }

I never faced issues in doing so (or at least my customers always paid me).

Il Pisanello
  • 117
  • 2
  • 4
  • you write you never encountered any problems, but it looks like a risky approach and misuse of API – Peter Lapisu Feb 09 '18 at 11:39
  • 1
    @PeterLapisu thanks for your reply. I agree with you this can be risky and quite a misuse of API but as long as it works without any big drawback I find it to be a good trade-off between clean code and easy of use. So it's just a solution, tough I agree with you, not the cleanest one. – Il Pisanello Feb 09 '18 at 12:27
  • It's been 5 years now and so far no problem with my method. – Il Pisanello Mar 27 '23 at 12:35