157

Can someone please instruct me on the easiest way to change the font size for the text in a UITableView section header?

I have the section titles implemented using the following method:

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

Then, I understand how to successfully change the section header height using this method:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section

I have the UITableView cells populated using this method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

However, I'm stuck as to how to actually increase the font size - or for that matter the font style - of the section header text?

Can someone please assist? Thanks.

Juan Boero
  • 6,281
  • 1
  • 44
  • 62
JRD8
  • 1,595
  • 2
  • 11
  • 6

12 Answers12

399

Another way to do this would be to respond to the UITableViewDelegate method willDisplayHeaderView. The passed view is actually an instance of a UITableViewHeaderFooterView.

The example below changes the font, and also centers the title text vertically and horizontally within the cell. Note that you should also respond to heightForHeaderInSection to have any changes to your header's height accounted for in the layout of the table view. (That is, if you decide to change the header height in this willDisplayHeaderView method.)

You could then respond to the titleForHeaderInSection method to reuse this configured header with different section titles.

Objective-C

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

    header.textLabel.textColor = [UIColor redColor];
    header.textLabel.font = [UIFont boldSystemFontOfSize:18];
    CGRect headerFrame = header.frame;
    header.textLabel.frame = headerFrame;
    header.textLabel.textAlignment = NSTextAlignmentCenter;
}

Swift 1.2

(Note: if your view controller is a descendant of a UITableViewController, this would need to be declared as override func.)

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

    header.textLabel.textColor = UIColor.redColor()
    header.textLabel.font = UIFont.boldSystemFontOfSize(18)
    header.textLabel.frame = header.frame
    header.textLabel.textAlignment = NSTextAlignment.Center
}

Swift 3.0

This code also ensures that the app doesn't crash if your header view is something other than a UITableViewHeaderFooterView:

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    guard let header = view as? UITableViewHeaderFooterView else { return }
    header.textLabel?.textColor = UIColor.red
    header.textLabel?.font = UIFont.boldSystemFont(ofSize: 18)
    header.textLabel?.frame = header.bounds
    header.textLabel?.textAlignment = .center
}
HotJard
  • 4,598
  • 2
  • 36
  • 36
Mark Semsel
  • 7,125
  • 3
  • 29
  • 27
  • 3
    This method worked much better for me than the one above – Plasma Apr 28 '14 at 13:02
  • 8
    Best answer I have seen. – phatmann May 06 '14 at 10:50
  • 2
    This would be the "proper" way to adjust the information, assuming there is no other reason to subclass (such as adding views, for example). Additionally, this method can be used to update the header text for Dynamic Type. Simply use: `header.textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];` and/or `header.detailTextLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];` along with the other steps needed (see here: http://captechconsulting.com/blog/john-szumski/ios-7-tutorial-series-dynamic-type) – leanne May 12 '14 at 03:39
  • 4
    This does not resize the header view, so if your font is larger or significantly different, such as Zapfino (don't ask why), it will cut the text out. If you have to calculate the size on your own, it's a mess and you shouldn't do it. – Léo Natan May 22 '14 at 14:55
  • @CocoaPriest Not crashing in my beta version, tho. (GM seed 2) – Patrick Bassut Oct 13 '14 at 23:03
  • @purrrminator for footers we can do a check for the class of the UIView type with `if ([view isKindOfClass:[UITableViewHeaderFooterView class]]) { ... }` because there are two views that are processed. One is a normal UIView (the view returned from viewForFooter) and the other is the UITableViewHeaderFooterView that we intend to modify. When trying to access the textLabel of the UIView it will exception on an invalid selector. Thus the need for checking which view is being passed in. – James C Oct 22 '15 at 20:07
  • Works for me in Swift 5. – bvh May 08 '19 at 04:28
  • to also control the background color of the header in general use header.contentView.backgroundColor = UIColor.whatevercoloryouwant, and of course for the textLabel itself header.textLabel.backgroundColor = UIColor.youchoose – Andy Weinstein May 04 '21 at 20:16
  • header.textLabel is deprecated ? – Suchith Aug 30 '23 at 06:35
123

Unfortunately, you may have to override this:

In Objective-C:

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

In Swift:

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

Try something like this:

In Objective-C:

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

    UILabel *myLabel = [[UILabel alloc] init];
    myLabel.frame = CGRectMake(20, 8, 320, 20);
    myLabel.font = [UIFont boldSystemFontOfSize:18];
    myLabel.text = [self tableView:tableView titleForHeaderInSection:section];

    UIView *headerView = [[UIView alloc] init];
    [headerView addSubview:myLabel];

    return headerView;
}

In Swift:

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

    let myLabel = UILabel()
    myLabel.frame = CGRect(x: 20, y: 8, width: 320, height: 20)
    myLabel.font = UIFont.boldSystemFont(ofSize: 18)
    myLabel.text = self.tableView(tableView, titleForHeaderInSection: section)

    let headerView = UIView()
    headerView.addSubview(myLabel)

    return headerView
}
tarleb
  • 19,863
  • 4
  • 51
  • 80
mosca1337
  • 2,409
  • 3
  • 24
  • 27
  • 6
    While this is a correct solution, be careful with this method. For a header longer than one line, you will have to perform the calculations of the height of the header in `tableView:heightForHeaderInSection:` which can be cumbersome. – Léo Natan Jan 12 '14 at 02:58
  • 3
    Tried this and while it works if you scroll the table up, the Header Label stays on the screen and overlays the cells. :( – Plasma Apr 28 '14 at 12:49
  • @Plasma that is the intended behavior of section headers and that's what happens even without using this method – trss May 03 '14 at 14:47
  • 2
    @trss I think you will find this is not expected behavior. I'm not talking about the header section staying there, only the label, and its super imposed on the cells as they pass under it making it look a real mess. I did find a better way to achieve this and will post it back once I find it again. – Plasma Jul 01 '14 at 13:26
  • @Plasma Oh, okay. I hadn't tried out this method. It's very weird that the header view doesn't float but the label alone does, if I understood you correctly. After all it is just a subview of the header view. How could it move away from its superview? Weird. This is the reason I avoid customizing much and keep it as minimal as possible. That's the reason I preferred Leo Natan's answer. – trss Jul 01 '14 at 17:57
  • 1
    @mosca1337 there is no need for creating another view, you can get the actual 'UITableViewHeaderFooterView' being displayed and adjust parameters. – Juan Boero Jul 07 '16 at 20:43
  • The label will stick when you scroll back up. – John Franke Sep 22 '17 at 21:04
  • You don't need to call `tableView:titleForHeaderInSection` here. Just override the view's `textLabel` property and return myLabel. The title string is provided by the `tableView:titleForHeaderInSection` function in the `UITableViewDataSource` protocol. It is then assigned to the header view's `textLabel`. – alekop Jan 09 '18 at 22:56
97

While mosca1337's answer is a correct solution, be careful with that method. For a header with text longer than one line, you will have to perform the calculations of the height of the header in tableView:heightForHeaderInSection: which can be cumbersome.

A much preferred method is to use the appearance API:

[[UILabel appearanceWhenContainedIn:[UITableViewHeaderFooterView class], nil] setFont:[UIFont boldSystemFontOfSize:28]];

This will change the font, while still leaving the table to manage the heights itself.

For optimal results, subclass the table view, and add it to the containment chain (in appearanceWhenContainedIn:) to make sure the font is only changed for the specific table views.

Léo Natan
  • 56,823
  • 9
  • 150
  • 195
  • Need to be careful about this as well, since it would change the font not only for the required table but for all other tables too, in case that is not desired. – trss May 03 '14 at 14:50
  • @trss Yes. It would be best to subclass `UITableViewHeaderFooterView` and only set appearance when contained in the subclass. I will edit the answer. – Léo Natan May 03 '14 at 15:04
  • 1
    If subclassing then you would anyway be returning a custom view from `- tableView:viewForHeaderInSection:` right? In which case the font can be set right there. This is what @mosca1337's solution does anyway. – trss May 03 '14 at 15:22
  • 1
    Haha, well I am a woozey after yesterday. Subclass the table view and add it to container list. ;-) – Léo Natan May 03 '14 at 15:30
  • 1
    Ah, that's nice. Better than a custom `UITableViewHeaderFooterView` just for a custom font. – trss May 03 '14 at 15:45
  • There is nothing obscure. If you have any questions, please let me know. – Léo Natan May 13 '14 at 04:01
  • 2
    This solution causes many bugs with calculating of real footer/header size. I can show some examples when the titles gets cutted while custom font is set up. – kas-kad Jun 27 '14 at 14:28
  • @purrrminator What bugs? It has worked correctly for me. – Léo Natan Jun 27 '14 at 15:20
  • @LeoNatan Standart Helvetica: http://take.ms/qKJ5U . Avenir: http://take.ms/ZyrFo . Standart Helvetica: http://take.ms/1i4On . Avenir: http://take.ms/1A4Hy . The Avenir font is `[UIFont fontWithName:@"AvenirNext-Medium" size:14]` – kas-kad Jun 28 '14 at 15:23
  • 1
    @LeoNatan, this worked fine for me until I tested it with the newest beta. Unfortunately, it turns out that `setFont:` is not intended to be called on a UILabel appearance proxy. Although UILabel inherits from UIView which conforms to the `UIAppearanceContainer` protocol, the method `setFont:` is not marked with `UI_APPEARANCE_SELECTOR` and should therefore not be used as such. Please have a look at both the headers of `UIView`and `UILabel` to see that e.g. `setBackgroundColor:` is marked with `UI_APPEARANCE_SELECTOR` while other methods are not. – Flo Jul 31 '14 at 12:17
  • 1
    FYI, this is working fine for me on iOS 8 - must've been a bug with the betas. – rebello95 Mar 09 '15 at 14:24
  • @trss regardless of everything else, there is no reason why you must return a custom view if subclassing. – entonio Jun 25 '15 at 00:32
  • 1
    This deserves two upvotes for being much more maintainable. – Kyle Clegg Oct 05 '16 at 23:13
  • 5
    **Swift 3**: `UILabel.appearance(whenContainedInInstancesOf: [UITableViewHeaderFooterView.self]).font = UIFont.boldSystemFont(ofSize: 28)` – Eric Hodgins Aug 17 '17 at 02:28
  • 3
    This doesn't resize the label correctly to fit the font on iOS 11. Also, scrolling up and down after loading the views resets them to the default font. – nickdnk Sep 05 '18 at 21:39
  • @nickdnk My guess is they moved to auto layout and didn’t take stuff into account. – Léo Natan Sep 06 '18 at 07:32
28

For iOS 7 I use this,


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

    header.textLabel.font = [UIFont boldSystemFontOfSize:10.0f];
    header.textLabel.textColor = [UIColor orangeColor];
}

Here is Swift 3.0 version with header resizing

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    if let header = view as? UITableViewHeaderFooterView {
        header.textLabel!.font = UIFont.systemFont(ofSize: 24.0)
        header.textLabel!.textColor = UIColor.orange          
    }
}
Maria
  • 4,471
  • 1
  • 25
  • 26
  • 7
    This will not size the header view to fit the new font. – Léo Natan Jan 06 '15 at 16:57
  • @LeoNatan How can we size the header view to fit the new font - can it be done in this method? – SAHM Dec 15 '15 at 21:58
  • I wanted to clarify that I did see your above answer but I only want to change the font to limit the size when a user selected font (accessibility) exceeds a certain size (so, not all of the time). I believe I need to check and possibly change the font in willDisplayHeaderView, so is there a way I could recalc the view height if the font is changed? – SAHM Dec 15 '15 at 22:02
22

Swift 3:

Simplest way to adjust only size:

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {

    let header = view as! UITableViewHeaderFooterView

    if let textlabel = header.textLabel {
        textlabel.font = textlabel.font.withSize(15)
    }
}
ziligy
  • 1,447
  • 16
  • 10
8

Swift 2.0:

  1. Replace default section header with fully customisable UILabel.

Implement viewForHeaderInSection, like so:

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

    let sectionTitle: String = self.tableView(tableView, titleForHeaderInSection: section)!
    if sectionTitle == "" {
      return nil
    }

    let title: UILabel = UILabel()

    title.text = sectionTitle
    title.textColor = UIColor(red: 0.0, green: 0.54, blue: 0.0, alpha: 0.8)
    title.backgroundColor = UIColor.clearColor()
    title.font = UIFont.boldSystemFontOfSize(15)

    return title
  }
  1. Alter the default header (retains default).

Implement willDisplayHeaderView, like so:

  override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {

    if let view = view as? UITableViewHeaderFooterView {
      view.backgroundView?.backgroundColor = UIColor.blueColor()
      view.textLabel!.backgroundColor = UIColor.clearColor()
      view.textLabel!.textColor = UIColor.whiteColor()
      view.textLabel!.font = UIFont.boldSystemFontOfSize(15)
    }
  }

Remember: If you're using static cells, the first section header is padded higher than other section headers due to the top of the UITableView; to fix this:

Implement heightForHeaderInSection, like so:

  override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

    return 30.0 // Or whatever height you want!
  }
Elliott Davies
  • 833
  • 9
  • 6
5

Here it is, You have to follow write a few methods here. #Swift 5

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    
    let header = view as? UITableViewHeaderFooterView
    header?.textLabel?.font = UIFont.init(name: "Montserrat-Regular", size: 14)
    header?.textLabel?.textColor = .greyishBrown
}

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

Have a good luck

Sreekanth G
  • 658
  • 6
  • 13
4

With this method you can set font size, font style and Header background also. there are have 2 method for this

First Method

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section{
        UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
        header.backgroundView.backgroundColor = [UIColor darkGrayColor];
        header.textLabel.font=[UIFont fontWithName:@"Open Sans-Regular" size:12];
        [header.textLabel setTextColor:[UIColor whiteColor]];
    }

Second Method

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
    UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 30)];
//    myLabel.frame = CGRectMake(20, 8, 320, 20);
    myLabel.font = [UIFont fontWithName:@"Open Sans-Regular" size:12];
    myLabel.text = [NSString stringWithFormat:@"   %@",[self tableView:FilterSearchTable titleForHeaderInSection:section]];

    myLabel.backgroundColor=[UIColor blueColor];
    myLabel.textColor=[UIColor whiteColor];
    UIView *headerView = [[UIView alloc] init];
    [headerView addSubview:myLabel];
    return headerView;
}
Anup Gupta
  • 1,993
  • 2
  • 25
  • 40
4

Swift 4 version of Leo Natan answer is

UILabel.appearance(whenContainedInInstancesOf: [UITableViewHeaderFooterView.self]).font = UIFont.boldSystemFont(ofSize: 28)

If you wanted to set a custom font you could use

if let font = UIFont(name: "font-name", size: 12) {
    UILabel.appearance(whenContainedInInstancesOf: [UITableViewHeaderFooterView.self]).font = font
}
Giorgio
  • 1,973
  • 4
  • 36
  • 51
1

Swift 2:

As OP asked, only adjust the size, not setting it as a system bold font or whatever:

func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        if let headerView = view as? UITableViewHeaderFooterView, textLabel = headerView.textLabel {

            let newSize = CGFloat(16)
            let fontName = textLabel.font.fontName
            textLabel.font = UIFont(name: fontName, size: newSize)
        }
    }
Juan Boero
  • 6,281
  • 1
  • 44
  • 62
0

The textView property on UITableViewHeaderFooterView is now deprecated. Documentation suggests that the correct way to change the font size is by using UIListContentConfiguration.

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    guard let view = view as? UITableViewHeaderFooterView else { fatalError() }
    var contentConfiguration = view.defaultContentConfiguration()
    contentConfiguration.textProperties.font = UIFont.systemFont(ofSize: 30)
    view.contentConfiguration = contentConfiguration
}

Note that if you are setting the title in titleForHeaderInSection, the it will be overwritten by the new content configuration. The title needs to be set with contentConfiguration.text = "<Your Title>".

I'll admit, I found this to be rather inflexible and ultimately returned my own, simple, header view in viewForHeaderInSection.

Rolf Locher
  • 163
  • 1
  • 13
-1

This is my solution with swift 5.

To fully control the header section view, you need to use the tableView(:viewForHeaderInsection::) method in your controller, as the previous post showed. However, there is a further step: to improve performance, apple recommend not generate a new view every time but to re-use the header view, just like reuse table cell. This is by method tableView.dequeueReusableHeaderFooterView(withIdentifier: ). But the problem I had is once you start to use this re-use function, the font won't function as expected. Other things like color, alignment all fine but just font. There are some discussions but I made it work like the following.

The problem is tableView.dequeueReusableHeaderFooterView(withIdentifier:) is not like tableView.dequeneReuseCell(:) which always returns a cell. The former will return a nil if no one available. Even if it returns a reuse header view, it is not your original class type, but a UITableHeaderFooterView. So you need to do the judgement and act according in your own code. Basically, if it is nil, get a brand new header view. If not nil, force to cast so you can control.

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let reuse_header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "yourHeaderID")
        if (reuse_header == nil) {
            let new_sec_header = YourTableHeaderViewClass(reuseIdentifier:"yourHeaderID")
            new_section_header.label.text="yourHeaderString"
            //do whatever to set color. alignment, etc to the label view property
            //note: the label property here should be your custom label view. Not the build-in labelView. This way you have total control.
            return new_section_header
        }
        else {
            let new_section_header = reuse_section_header as! yourTableHeaderViewClass
            new_sec_header.label.text="yourHeaderString"
            //do whatever color, alignment, etc to the label property
            return new_sec_header}

    }
JerryH
  • 1
  • 1