Customize UITableView header section
Asked Answered
E

24

146

I want to customize UITableView header for each section. So far, I've implemented

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

this UITabelViewDelegate method. What I want to do is to get current header for each section and just add UILabel as a subview.

So far, I'm not able to accomplish that. Because, I couldn't find anything to get default section header. First question,is there any way to get default section header?

If it's not possible, I need to create a container view which is a UIView but,this time I need to set default background color,shadow color etc. Because, if you look carefully into section's header, it's already customized.

How can I get these default values for each section header?

Escalator answered 25/3, 2013 at 9:23 Comment(4)
What's wrong with using tableView:titleForHeaderInSection: ?Roentgenology
It returns a NSString, i need to set custom font so, i can't if i use tableView:titleForHeaderInSection:Escalator
Or you can use images to mimic the default section headers. teehanlax.com/blog/ios-6-gui-psd-iphone-5Slipway
@limon: How to implement section header: https://mcmap.net/q/160866/-design-uitableview-39-s-section-header-in-interface-builderHipped
L
293

You can try this:

 -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 18)];
    /* Create custom view to display section header... */
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, tableView.frame.size.width, 18)];
    [label setFont:[UIFont boldSystemFontOfSize:12]];
     NSString *string =[list objectAtIndex:section];
    /* Section header is in 0th index... */
    [label setText:string];
    [view addSubview:label];
    [view setBackgroundColor:[UIColor colorWithRed:166/255.0 green:177/255.0 blue:186/255.0 alpha:1.0]]; //your background color...
    return view;
}
Lauretta answered 25/3, 2013 at 9:31 Comment(8)
thats your bg color watever color you want to set you canLauretta
That's the issue, i've already done what you wrote. But, i don't know default background color of section header,which is kind of gray. But, i need it to be exactly default section header.Escalator
hey come on use Digital color meterLauretta
make sure to set the UILabel's backgroundColor as well. I know I was slightly confused when my background wasn't turning clear for me.Stephine
Is it a tableView instead of tableview ?Entrepreneur
what is list in line NSString *string =[list objectAtIndex:section]; anybody can tell mePiggin
its [UIColor groupTableViewBackgroundColor];Ventriloquist
NGL, i copy pasted this code to my app and it works.Cora
I
45

The selected answer using tableView :viewForHeaderInSection: is correct.

Just to share a tip here.

If you are using storyboard/xib, then you could create another prototype cell and use it for your "section cell". The code to configure the header is similar to how you configure for row cells.

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    static NSString *HeaderCellIdentifier = @"Header";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:HeaderCellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:HeaderCellIdentifier];
    }

    // Configure the cell title etc
    [self configureHeaderCell:cell inSection:section];

    return cell;
}
Illimani answered 5/5, 2015 at 6:38 Comment(7)
there are a number of things wrong w/ this solution. First of which is the fact that if you implement "tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool", you'll notice that the section header will move along with the row when you slide. To avoid this, you must return cell.contentView instead. The Bigger issue is the fact that with this solution, the app will crash when you long press the section header. Correct way is to create a nib that extends UITableViewHeaderFooterView, register it w/ the tableview and return it in this method. Tested on iOS8Extremist
@Extremist The solution is using viewForHeaderInSection not canEditRowAtIndexPath as you mentioned. I never verify the crash you said, but could you enlighten how a long press will cause a crash?Illimani
what I meant was that if you implement this solution AND implement canEditRowAtIndexPath, you will see that the header will also slide with with the topmost row that you are deleting if you do not return cell.contentView. See this SO post: #26010222 The long press causes a crash because a message tries to get sent to a deallocated object. See this SO post: #27622790Extremist
Please don't ever use UITableViewCell as a header view. You'll get very difficult to debug visual glitches - header will sometimes disappear because of how cells are dequeued and you'll be looking for hours why is that until you realize UITableViewCell does not belong in UITableView header.Armhole
Using a UITableViewCell as a header is simply wrong.Impedimenta
Why dequeueReusableCellWithIdentifier and not dequeueReusableHeaderFooterView?Fish
Using this solution results in errors with either the cell being nil or the label inside it being nil. This seems to be a wrong solution.Middleman
L
34

Swift version of Lochana Tejas answer:

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let view = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 18))
    let label = UILabel(frame: CGRectMake(10, 5, tableView.frame.size.width, 18))
    label.font = UIFont.systemFontOfSize(14)
    label.text = list.objectAtIndex(indexPath.row) as! String
    view.addSubview(label)
    view.backgroundColor = UIColor.grayColor() // Set your background color

    return view
}
Luscious answered 10/1, 2016 at 16:28 Comment(2)
how to make label height dynamic as per the text which is inside the view?Heiskell
The override keyword is redundant. What is more, consider reusing header views rather than re-creating them.Zooplankton
A
17

If you use default header view you can only change the text on it with

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

For Swift:

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

If you want to customize the view you need to create a new one your self.

Anima answered 25/3, 2013 at 9:46 Comment(0)
O
10

why not use UITableViewHeaderFooterView?

Otorhinolaryngology answered 28/9, 2013 at 15:44 Comment(3)
You can only use this if you do not also use -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section.Perjury
Perfectly valid answer. Also, using UITableViewHeaderFooterView benefits from view recycling just like cells.Precede
@dmarsi I have found no evidence of them being deprecated.Junction
G
9

If headerInSection isn't show, can try this.

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 45;
}

This returns a height for the header of a given section.

Garpike answered 17/12, 2015 at 2:57 Comment(2)
Mind elaborating your answer?Faustofaustus
The header section wont show unless you specify with a method hook the 'height' of the section header. UITableView defaults to not showing headers if no height is specified. @FaustofaustusIlluminati
G
6

Swift 3 version of lochana and estemendoza answers:

override 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:10, y:5, width:tableView.frame.size.width, height:18))
    label.font = UIFont.systemFont(ofSize: 14)
    label.text = "This is a test";
    view.addSubview(label);
    view.backgroundColor = UIColor.gray;
    return view

}

Also, be advised that you ALSO have to implement:

override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 100;
}
Gruelling answered 26/6, 2017 at 18:26 Comment(0)
U
6

The other answers do a good job of recreating the default header view, but don't actually answer your main question:

is there any way to get default section header ?

There is a way - just implement tableView:willDisplayHeaderView:forSection: in your delegate. The default header view will be passed into the second parameter, and from there you can cast it to a UITableViewHeaderFooterView and then add/change subviews as you wish.

Obj-C

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    UITableViewHeaderFooterView *headerView = (UITableViewHeaderFooterView *)view;

    // Do whatever with the header view... e.g.
    // headerView.textLabel.textColor = [UIColor whiteColor]
}

Swift

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
{
    let headerView = view as! UITableViewHeaderFooterView

    // Do whatever with the header view... e.g.
    // headerView.textLabel?.textColor = UIColor.white
}
Unscathed answered 28/6, 2017 at 22:26 Comment(2)
You don't need to cast it. You can just add what you want to the view. In fact, creating a new object will do nothing unless you assign it to view.Impedimenta
@AlexZavatone That's right, you don't need to cast it if you're just adding views. It's helpful if you want to customise some of the default views like the text label.Unscathed
V
5

This is the easiest solution possible. The following code can be used directly for creating a custom section header.

 -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    SectionHeaderTableViewCell *headerView = [tableView dequeueReusableCellWithIdentifier:@"sectionHeader"];

    //For creating a drop menu of rows from the section
    //==THIS IS JUST AN EXAMPLE. YOU CAN REMOVE THIS IF-ELSE.==
    if (![self.sectionCollapsedArray[section] boolValue])
    {
        headerView.imageView.image = [UIImage imageNamed:@"up_icon"];
    }
    else
    {
        headerView.imageView.image = [UIImage imageNamed:@"drop_icon"];
    }

    //For button action inside the custom cell
    headerView.dropButton.tag = section;
    [headerView.dropButton addTarget:self action:@selector(sectionTapped:) forControlEvents:UIControlEventTouchUpInside];

    //For removing long touch gestures.
    for (UIGestureRecognizer *recognizer in headerView.contentView.gestureRecognizers)
    {
        [headerView.contentView removeGestureRecognizer:recognizer];
        [headerView removeGestureRecognizer:recognizer];
    }

    return headerView.contentView;
}

NOTE: SectionHeaderTableViewCell is a custom UITableViewCell created in Storyboard.

Vadnee answered 24/6, 2015 at 15:5 Comment(2)
SectionHeaderTableViewCell - use of undeclared identifierViniculture
@BorisGafurov SectionHeaderTableViewCell is just an example name that I gave my UITableViewCell, which, I created in the storyboard.Vadnee
A
5

Try this......

override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) 
{
    // Background view is at index 0, content view at index 1
    if let bgView = view.subviews[0] as? UIView
    {
        // do your stuff
    }

    view.layer.borderColor = UIColor.magentaColor().CGColor
    view.layer.borderWidth = 1
}
Apologetic answered 9/7, 2015 at 13:43 Comment(0)
B
4
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    //put your values, this is part of my code
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 30.0f)];
    [view setBackgroundColor:[UIColor redColor]];
    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 5, 150, 20)];
    [lbl setFont:[UIFont systemFontOfSize:18]];
    [lbl setTextColor:[UIColor blueColor]];
    [view addSubview:lbl];

    [lbl setText:[NSString stringWithFormat:@"Section: %ld",(long)section]];

    return view;
}
Brinna answered 18/3, 2015 at 13:19 Comment(0)
S
4

Full 2019 example to copy and paste

First set "Grouped" on storyboard: it has to happen at init time, you can't really set it later, so it's easier to remember to do it on storyboard:

enter image description here

Next,

Must implement heightForHeaderInSection due to Apple bug.

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

There is still an Apple bug - for ten years now - where it simply won't show the first header (i.e., index 0) if you don't have heightForHeaderInSection call.

So, tableView.sectionHeaderHeight = 70 simply doesn't work, it's broken.

Setting a frame achieves nothing:

In viewForHeaderInSection simply create a UIView().

It is pointless / achieves nothing if you UIView(frame ...) since iOS simply sets the size of the view as determined by the table.

So the first line of viewForHeaderInSection will be simply let view = UIView() and that is the view you return.

func tableView(_ tableView: UITableView,
                       viewForHeaderInSection section: Int) -> UIView? {
    let view = UIView()
    
    let l = UILabel()
    view.addSubview(l)
    l.bindEdgesToSuperview()
    l.backgroundColor = .systemOrange
    l.font = UIFont.systemFont(ofSize: 15)
    l.textColor = .yourClientsFavoriteColor
    
    switch section {
    case 0:
        l.text =  "First section on screen"
    case 1:
        l.text =  "Here's the second section"
    default:
        l.text =  ""
    }
    
    return view
}

That's it - anything else is a time waste.

Another "fussy" Apple issue.


The convenience extension used above is:

extension UIView {
    
    // incredibly useful:
    
    func bindEdgesToSuperview() {
        
        guard let s = superview else {
            preconditionFailure("`superview` nil in bindEdgesToSuperview")
        }
        
        translatesAutoresizingMaskIntoConstraints = false
        leadingAnchor.constraint(equalTo: s.leadingAnchor).isActive = true
        trailingAnchor.constraint(equalTo: s.trailingAnchor).isActive = true
        topAnchor.constraint(equalTo: s.topAnchor).isActive = true
        bottomAnchor.constraint(equalTo: s.bottomAnchor).isActive = true
    }
}
Salinas answered 20/10, 2019 at 19:43 Comment(0)
T
2

If I were you, I would make a method which returns an UIView given a NSString to contain. For example

+ (UIView *) sectionViewWithTitle:(NSString *)title;

In the implementation of this method create a UIView, add a UILabel to it with the properties you want to set, and of course set its title to the given one.

Tightwad answered 25/3, 2013 at 9:32 Comment(3)
Yes, i can do that, but my question is how can i get default section header background,shadow value, the rest is easy to implement.Escalator
what do you mean by default section header backgroundLauretta
Well, the easiest would be to use the Digital Color Meter application to get the colors you want. Taking them by code would be tough, as far as I can tell...Tightwad
M
2

@samwize's solution in Swift (so upvote him!). Brilliant using same recycling mechanism also for header/footer sections:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let settingsHeaderSectionCell:SettingsHeaderSectionCell = self.dequeueReusableCell(withIdentifier: "SettingsHeaderSectionCell") as! SettingsHeaderSectionCell

    return settingsHeaderSectionCell
}
Merola answered 3/3, 2017 at 10:31 Comment(0)
T
2
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
    if([view isKindOfClass:[UITableViewHeaderFooterView class]]){

        UITableViewHeaderFooterView *headerView = view;

        [[headerView textLabel] setTextColor:[UIColor colorWithHexString:@"666666"]];
        [[headerView textLabel] setFont:[UIFont fontWithName:@"fontname" size:10]];
    }
}

If you want to change the font of the textLabel in your section header you want to do it in willDisplayHeaderView. To set the text you can do it in viewForHeaderInSection or titleForHeaderInSection. Good luck!

Thamora answered 22/9, 2017 at 22:4 Comment(0)
S
1

Magically add Table View Header in swift

Recently I tried this.

I needed one and only one header in the whole UITableView.

Like I wanted a UIImageView on the top of the TableView. So I added a UIImageView on top of the UITableViewCell and automatically it was added as a tableViewHeader. Now I connect the ImageView to the ViewController and added the Image.

I was confused because I did something like this for the first time. So to clear my confusion open the xml format of the MainStoryBoard and found the Image View was added as a header.

It worked for me. Thanks xCode and swift.

Strobe answered 27/11, 2015 at 11:28 Comment(0)
J
1

call this delegate method

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{

return @"Some Title";
}

this will give a chance to automatically add a default header with dynamic title .

You may use reusable and customizable header / footer .

https://github.com/sourov2008/UITableViewCustomHeaderFooterSection

Javanese answered 27/10, 2017 at 19:0 Comment(0)
P
1

swif 4.2

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    guard let header = view as? UITableViewHeaderFooterView else { return }

    header.textLabel?.textAlignment = .center // for all sections

    switch section {
    case 1:  //only section No.1
        header.textLabel?.textColor = .black
    case 3:  //only section No.3
        header.textLabel?.textColor = .red
    default: //
        header.textLabel?.textColor = .yellow
    }
}
Panacea answered 14/11, 2018 at 17:22 Comment(0)
J
0

besides to titleForHeaderInSection, you can simply change view of header, footer. check my comment here: Change UITable section backgroundColor without loosing section Title

Joel answered 13/3, 2015 at 22:46 Comment(0)
A
0

If you just want to add title to the tableView header dont add a view. In swift 3.x the code goes like this:

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    var lblStr = ""
    if section == 0 {
        lblStr = "Some String 1"
    }
    else if section == 1{
        lblStr = "Some String 2"
    }
    else{
        lblStr = "Some String 3"
    }
    return lblStr
}

You may implement an array to fetch the title for the headers.

Acne answered 10/3, 2017 at 13:10 Comment(0)
K
0

Going back to the original question (4 years later), rather than rebuilding your own section header, iOS can simply call you (with willDisplayHeaderView:forSection:) right after it's built the default one. For example, I wanted to add a graph button on right edge of section header:

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
    UITableViewHeaderFooterView * header = (UITableViewHeaderFooterView *) view;
    if (header.contentView.subviews.count >  0) return; //in case of reuse
    CGFloat rightEdge = CGRectGetMaxX(header.contentView.bounds);
    UIButton * button = [[UIButton alloc] initWithFrame:CGRectMake(rightEdge - 44, 0, 44, CGRectGetMaxY(header.contentView.bounds))];
    [button setBackgroundImage:[UIImage imageNamed:@"graphIcon"] forState:UIControlStateNormal];
    [button addTarget:self action:@selector(graphButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
    [view addSubview:button];
}
Kaceykachina answered 8/5, 2017 at 16:6 Comment(0)
I
0

Use tableView: willDisplayHeaderView: to customize the view when it is about to be displayed.

This gives you the advantage of being able to take the view that was already created for the header view and extend it, instead of having to recreate the whole header view yourself.

Here is an example that colors the header section based on a BOOL and adds a detail text element to the header.

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
//    view.tintColor = [UIColor colorWithWhite:0.825 alpha:1.0]; // gray
//    view.tintColor = [UIColor colorWithRed:0.825 green:0.725 blue:0.725 alpha:1.0]; // reddish
//    view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0]; // pink

    // Conditionally tint the header view
    BOOL isMyThingOnOrOff = [self isMyThingOnOrOff];

    if (isMyThingOnOrOff) {
        view.tintColor = [UIColor colorWithRed:0.725 green:0.925 blue:0.725 alpha:1.0];
    } else {
        view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0];
    }

    /* Add a detail text label (which has its own view to the section header… */
    CGFloat xOrigin = 100; // arbitrary
    CGFloat hInset = 20;
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(xOrigin + hInset, 5, tableView.frame.size.width - xOrigin - (hInset * 2), 22)];

    label.textAlignment = NSTextAlignmentRight;

    [label setFont:[UIFont fontWithName:@"Helvetica-Bold" size:14.0]
    label.text = @"Hi.  I'm the detail text";

    [view addSubview:label];
}
Impedimenta answered 9/11, 2017 at 0:15 Comment(0)
S
0

Swift 4.2

In Swift 4.2 the name of table is a little changed.

    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: 10, y: 5, width: tableView.frame.size.width, height: 18))
        label.font = UIFont.systemFont(ofSize: 14)
        label.text = list.objectAtIndex(section) as! String
        view.addSubview(label)
        view.backgroundColor = UIColor.gray // Set your background color

        return view
    }
Spaghetti answered 11/3, 2020 at 11:29 Comment(0)
C
0

Code for Swift 5

We can implement this by using two tableView delegate functions:

1] We can give custom height for the section:

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

2] Then we can create custom header:

 func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let sectionV = UIView.init(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 48) )
    let titleLbl = UILabel.init(frame: CGRect(x: 25, y: 24, width: tableView.frame.width-150, height: 20) )
    let viewAllBtn = UIButton.init(frame: CGRect(x: tableView.frame.width-150, y: 15, width: self.view.frame.width - titleLbl.frame.width, height: 45))
    viewAllBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15)
    viewAllBtn.setTitle("View All", for: .normal)
    viewAllBtn.setTitleColor(.systemBlue, for: .normal)
    viewAllBtn.tag = section
    titleLbl.text = dashboardTempData.data?[section].title
    titleLbl.font = UIFont.systemFont(ofSize: 21, weight: UIFont.Weight.medium)
    sectionV.backgroundColor = .systemBackground
    sectionV.addSubview(titleLbl)
    sectionV.addSubview(viewAllBtn)
    sectionV.bringSubviewToFront(viewAllBtn)
    return sectionV
}

It will create a Label and Button with a section header height of 49

Cynthea answered 2/6, 2021 at 15:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.