Changing Font Size For UITableView Section Headers
Asked Answered
B

12

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.

Bonnie answered 6/11, 2013 at 1:22 Comment(1)
Swift versionBernabernadene
H
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
}
Hildick answered 6/11, 2013 at 1:47 Comment(8)
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.Brunner
Tried this and while it works if you scroll the table up, the Header Label stays on the screen and overlays the cells. :(Earp
@Earp that is the intended behavior of section headers and that's what happens even without using this methodHowerton
@Howerton 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.Earp
@Earp 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.Howerton
@Hildick there is no need for creating another view, you can get the actual 'UITableViewHeaderFooterView' being displayed and adjust parameters.Bernabernadene
The label will stick when you scroll back up.Mono
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.Alonso
D
400

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
}
Daddy answered 11/4, 2014 at 19:55 Comment(9)
This method worked much better for me than the one aboveEarp
Best answer I have seen.Barbershop
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: captechconsulting.com/blog/john-szumski/…)Explicative
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.Brunner
@CocoaPriest Not crashing in my beta version, tho. (GM seed 2)Permeability
@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.Bassoon
Works for me in Swift 5.Amalea
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.youchooseMagnetics
header.textLabel is deprecated ?Lahr
H
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
}
Hildick answered 6/11, 2013 at 1:47 Comment(8)
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.Brunner
Tried this and while it works if you scroll the table up, the Header Label stays on the screen and overlays the cells. :(Earp
@Earp that is the intended behavior of section headers and that's what happens even without using this methodHowerton
@Howerton 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.Earp
@Earp 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.Howerton
@Hildick there is no need for creating another view, you can get the actual 'UITableViewHeaderFooterView' being displayed and adjust parameters.Bernabernadene
The label will stick when you scroll back up.Mono
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.Alonso
D
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.

Disendow answered 12/1, 2014 at 3:3 Comment(16)
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.Howerton
@Howerton Yes. It would be best to subclass UITableViewHeaderFooterView and only set appearance when contained in the subclass. I will edit the answer.Brunner
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.Howerton
Haha, well I am a woozey after yesterday. Subclass the table view and add it to container list. ;-)Brunner
Ah, that's nice. Better than a custom UITableViewHeaderFooterView just for a custom font.Howerton
There is nothing obscure. If you have any questions, please let me know.Brunner
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.Adjust
@purrrminator What bugs? It has worked correctly for me.Brunner
@LeoNatan Standart Helvetica: take.ms/qKJ5U . Avenir: take.ms/ZyrFo . Standart Helvetica: take.ms/1i4On . Avenir: take.ms/1A4Hy . The Avenir font is [UIFont fontWithName:@"AvenirNext-Medium" size:14]Adjust
@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 UIViewand UILabel to see that e.g. setBackgroundColor: is marked with UI_APPEARANCE_SELECTOR while other methods are not.Cloistral
FYI, this is working fine for me on iOS 8 - must've been a bug with the betas.Lawler
@Howerton regardless of everything else, there is no reason why you must return a custom view if subclassing.Leveller
This deserves two upvotes for being much more maintainable.Backsheesh
Swift 3: UILabel.appearance(whenContainedInInstancesOf: [UITableViewHeaderFooterView.self]).font = UIFont.boldSystemFont(ofSize: 28)Commissar
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.Plentiful
@Plentiful My guess is they moved to auto layout and didn’t take stuff into account.Brunner
F
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          
    }
}
Fina answered 29/9, 2014 at 20:0 Comment(3)
This will not size the header view to fit the new font.Brunner
@LeoNatan How can we size the header view to fit the new font - can it be done in this method?Jun
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?Jun
U
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)
    }
}
Uganda answered 22/9, 2016 at 16:11 Comment(2)
That is the easiest way I am looking for.Catechetical
Works in swift 4! Don’t forget "override func.."Peculate
G
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!
  }
Gallinacean answered 27/12, 2015 at 15:11 Comment(0)
C
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

Casseycassi answered 9/9, 2020 at 17:37 Comment(0)
U
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;
}
Unjust answered 15/12, 2016 at 10:56 Comment(0)
K
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
}
Keeler answered 11/1, 2018 at 14:4 Comment(1)
This doesn't resize the frame, unfortunately.Plentiful
B
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)
        }
    }
Bernabernadene answered 7/7, 2016 at 20:53 Comment(0)
A
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.

Avisavitaminosis answered 4/3, 2023 at 5:15 Comment(0)
T
-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}

    }
Tamp answered 23/5, 2020 at 5:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.