74

I need to add custom header to my table

I try this

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

    let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 18))
    let label = UILabel(frame: CGRect(x: 20, y: 20, width: 50, height: 50))
    label.text = "TEST TEXT"
    label.textColor = UIColor.whiteColor()

    self.view.addSubview(view)

    return view
}

but this doesn't work, I see nothing on table

What am I doing wrong ? Or maybe there is another ways ?

Anbu.Karthik
  • 82,064
  • 23
  • 174
  • 143
Alexey K
  • 6,537
  • 18
  • 60
  • 118
  • 5
    Adding `view` to `self.view` is not necessary. It will be removed from there and added to the table view. – Cyrille Aug 12 '15 at 12:20
  • @Cyrille I'm not sure why you think the view would be removed after it's been programmatically added to the subviews array, but it seems to me it would simply be added to the view hierarchy in two different places, which would lead to undefined behavior. – jlehr Aug 12 '15 at 12:40
  • 1
    Nope. A view can only have one superview at a time. If you add a view anywhere, it will first be removed from where it was previously. – Cyrille Aug 12 '15 at 13:31

7 Answers7

81

The best working Solution of adding Custom header view in UITableView for section in swift 4 is --

#1 first Use method ViewForHeaderInSection as below -

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: tableView.frame.width, height: 50))
        
        let label = UILabel()
        label.frame = CGRect.init(x: 5, y: 5, width: headerView.frame.width-10, height: headerView.frame.height-10)
        label.text = "Notification Times"
        label.font = .systemFont(ofSize: 16)
        label.textColor = .yellow
        
        headerView.addSubview(label)
        
        return headerView
    }

#2 Also Don't forget to set Height of the header using heightForHeaderInSection UITableView method -

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 50
    }

and you're all set Check it here in image

Kqtr
  • 5,824
  • 3
  • 25
  • 32
Mohit G.
  • 1,157
  • 2
  • 12
  • 22
  • 1
    Please let me know if we can improve this – Mohit G. Oct 16 '18 at 09:54
  • 3
    You dont have to add additional view there you can create UILabel directly as header. **let headerView = UILabel.init(frame: CGRect.init(x: 0, y: 0, width: tableView.frame.width, height: 50)), headerView.text = "Notification Times"** – Hope Oct 20 '19 at 06:04
  • 1
    Thanks for writing back @Hope, yes we can do same as you suggested, I just make it because I need to follow my UI as per Zeplin (the reason I wrote "my custom Colour & font") :) – Mohit G. Oct 21 '19 at 07:47
  • 1
    view Hide with Scrolling issue – Krunal Nagvadia Jan 27 '20 at 10:00
  • 1
    Hi @KrunalNagvadia, what issue you're facing? – Mohit G. Jan 27 '20 at 11:32
  • 1
    When i Scroll my headerView is disappear. This is my code `func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { return headerView }` – Krunal Nagvadia Jan 27 '20 at 11:38
  • 1
    @KrunalNagvadia I believe you want to keep the header view visible until all the cells are visible for the section. for the same, you need to change the table style in attribute inspector as Grouped. Hope I answer you, if still not please be specific about your problem and the code you tried. – Mohit G. Jan 27 '20 at 11:55
34

Did you set the section header height in the viewDidLoad?

self.tableView.sectionHeaderHeight = 70

Plus you should replace

self.view.addSubview(view)

by

view.addSubview(label)

Finally you have to check your frames

let view = UIView(frame: CGRect.zeroRect)

and eventually the desired text color as it seems to be currently white on white.

Tanguy G.
  • 2,143
  • 19
  • 18
34

If you are using custom cell as header, add the following.

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

        let headerView = UIView()
        let headerCell = tableView.dequeueReusableCell(withIdentifier: "customTableCell") as! CustomTableCell
        headerView.addSubview(headerCell)
        return headerView
    }

If you want to have simple view, add the following.

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView:UIView =  UIView()
    return headerView
}
Alvin George
  • 14,148
  • 92
  • 64
34

This worked for me - Swift 3

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

        let headerCell = tableView.dequeueReusableCell(withIdentifier: "customTableCell") as! CustomTableCell
        return headerCell
    }

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 40
}
Codetard
  • 2,441
  • 28
  • 34
Basir Alam
  • 1,332
  • 20
  • 24
  • Brilliant. I've added a header cell manually and had to offset the cells in the appropriate delegate methods. This'll save some work – froggomad Dec 31 '19 at 15:14
  • 3
    It worked for me, when I add `heightForHeaderInSection` along with `viewForHeaderInSection`. I have created another table cell in the tableview of storyboard and given different identifier. This worked! – Sravan Feb 12 '20 at 13:52
26

If you are willing to use custom table header as table header, try the followings....

Updated for swift 3.0

Step 1

Create UITableViewHeaderFooterView for custom header..

import UIKit

class MapTableHeaderView: UITableViewHeaderFooterView {

    @IBOutlet weak var testView: UIView!

}

Step 2

Add custom header to UITableView

    override func viewDidLoad() {
            super.viewDidLoad()

            tableView.delegate = self
            tableView.dataSource = self

            //register the header view

            let nibName = UINib(nibName: "CustomHeaderView", bundle: nil)
            self.tableView.register(nibName, forHeaderFooterViewReuseIdentifier: "CustomHeaderView")


    }

    extension BranchViewController : UITableViewDelegate{

    }

    extension BranchViewController : UITableViewDataSource{

        func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
            return 200
        }

        func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
            let headerView = self.tableView.dequeueReusableHeaderFooterView(withIdentifier: "CustomHeaderView" ) as! MapTableHeaderView

            return headerView
        }

        func tableView(_ tableView: UITableView, numberOfRowsInSection section: 

    Int) -> Int {
            // retuen no of rows in sections
        }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
            // retuen your custom cells    
        }

        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        }

        func numberOfSections(in tableView: UITableView) -> Int {
            // retuen no of sections
        }

        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            // retuen height of row
        }


    }
GayashanK
  • 1,195
  • 2
  • 13
  • 27
  • Very Nice bro. I learnt to manage code using extension as well. Thanks for the full code format! :) – iHarshil Apr 05 '19 at 13:18
8

add label to subview of custom view, no need of self.view.addSubview(view), because viewForHeaderInSection return the UIView

view.addSubview(label)
Anbu.Karthik
  • 82,064
  • 23
  • 174
  • 143
  • You need to add the label, yes ; but adding `view` to `self.view` is not necessary. It will be removed from there and added to the table view. – Cyrille Aug 12 '15 at 12:20
4

I have had some problems in Swift 5 with this. When using this function I had a wrong alignment with the header cell:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
     let headerCell = tableView.dequeueReusableCell(withIdentifier: "customTableCell") as! CustomTableCell
     return headerCell
}

The cell view was shown with a bad alignment and the top part of the tableview was shown. So I had to make some tweak like this:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
     let headerView = UIView.init(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 90))
     let headerCell = tableView.dequeueReusableCell(withIdentifier: "YOUR_CELL_IDENTIFIER")
     headerCell?.frame = headerView.bounds
     headerView.addSubview(headerCell!)
     return headerView
 }

I am having this problem in Swift 5 and Xcode 12.0.1, I don't know if it is just a problem for me or it is a bug. Hope it helps ! I have lost a morning...

Diego Jiménez
  • 1,398
  • 1
  • 15
  • 26