Troubles with changing the font size in UITableViewHeaderFooterView
Asked Answered
O

4

21

Here is the problem,

I subclass a UITableViewHeaderFooterView and want to change the font size:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        self.textLabel.textColor = [UIColor colorWithWhite:0.8 alpha:1.0];
        //the font is not working
        self.textLabel.font = [UIFont systemFontOfSize:20];
        NSLog(@"aaa%@", self.textLabel.font);
    }
    return self;
}

The color stuff works fine, but the font didn't change, so I log the dequeue:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UITableViewHeader *headerView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:MWDrawerHeaderReuseIdentifier];
    headerView.textLabel.text = self.sectionTitles[@(section)];
    NSLog(@"bbb%@", headerView.textLabel.font);
    return headerView;
}

The font still goes right in here, so I log in didLayoutsubviews:

-(void)viewDidLayoutSubviews
{
    UITableViewHeaderFooterView *head = [self.tableView headerViewForSection:0];
    NSLog(@"ccc%@", head.textLabel.font);
}

and the font size is magically CHANGED back to the default!!! But I didn't do anything between there, and If I change the font size again in viewDidLayoutSubviews, the font becomes right.

It drives me CRAZY!!!

And I do the same font changing when subclass the cell, and it works fine! so can anyone tell me what's going on? Thanks!

Here is the log:

2014-02-09 16:02:03.339 InternWell[33359:70b] aaa<UICTFont: 0x8da4290> font-family: ".HelveticaNeueInterface-M3"; font-weight: normal; font-style: normal; font-size: 20.00pt

2014-02-09 16:02:03.339 InternWell[33359:70b] bbb<UICTFont: 0x8da4290> font-family: ".HelveticaNeueInterface-M3"; font-weight: normal; font-style: normal; font-size: 20.00pt

2014-02-09 16:02:03.341 InternWell[33359:70b] aaa<UICTFont: 0x8da4290> font-family: ".HelveticaNeueInterface-M3"; font-weight: normal; font-style: normal; font-size: 20.00pt

2014-02-09 16:02:03.342 InternWell[33359:70b] bbb<UICTFont: 0x8da4290> font-family: ".HelveticaNeueInterface-M3"; font-weight: normal; font-style: normal; font-size: 20.00pt

2014-02-09 16:02:03.343 InternWell[33359:70b] ccc<UICTFont: 0x8d22650> font-family: ".HelveticaNeueInterface-MediumP4"; font-weight: bold; font-style: normal; font-size: 14.00pt

2014-02-09 16:02:03.343 InternWell[33359:70b] ccc<UICTFont: 0x8d22650> font-family: ".HelveticaNeueInterface-MediumP4"; font-weight: bold; font-style: normal; font-size: 14.00pt
Orvah answered 9/2, 2014 at 8:7 Comment(1)
Same issue even without subclassing UITableViewHeaderFooterView, a font that is set gets reset by the time the view is presented. Checked on iOS 9.3.Pitterpatter
W
15

It doesn't seem like the right place to put it, but you can change the font in the layoutSubviews method of your UITableViewHeaderFooterView subclass and it will apply properly.

- (void)layoutSubviews {
    [super layoutSubviews];

    // Font
    self.textLabel.font = [UIFont systemFontOfSize:20];
}
Winny answered 15/4, 2014 at 23:50 Comment(2)
UITableViewHeaderFooterView does naughty things in -layoutSubviews, including changing the color of the textLabel. I wouldn’t be surprised if it changes the font as well. This was the workaround I arrived at as well, but it seems like a bug.Rankins
There must be a better way to do this - layoutSubviews is supposed to only contain layout, it can be called several times in a single rendering loop, and as such, it's not recommended to place anything other than layout here; I assume the better approach is to either create a custom title label, or update the font in willDisplayHeaderView.Freezer
M
28

You could implement tableView:willDisplayHeaderView and change the font in kind of this way:

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
    if(section == ...)
    {
        UITableViewHeaderFooterView *headerView = (UITableViewHeaderFooterView *)view;
        NSAttributedString *headerText = ... ;
        headerView.textLabel.attributedText = headerText;
    }
}
Malanie answered 12/2, 2015 at 21:32 Comment(2)
Much nicer solution than the selected answer. I just did this in Swift, works great (and no need to subclass): override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { if let header = view as? UITableViewHeaderFooterView { header.textLabel.font = UIFont.boldSystemFontOfSize(22.0) } }Heal
I wouldn't say this is nicer at all. You're badly separating concerns by modifying the layout of a view ~outside~ the file in which you are describing the rest of the view's layout. Very bad code smell for me.Rabies
W
15

It doesn't seem like the right place to put it, but you can change the font in the layoutSubviews method of your UITableViewHeaderFooterView subclass and it will apply properly.

- (void)layoutSubviews {
    [super layoutSubviews];

    // Font
    self.textLabel.font = [UIFont systemFontOfSize:20];
}
Winny answered 15/4, 2014 at 23:50 Comment(2)
UITableViewHeaderFooterView does naughty things in -layoutSubviews, including changing the color of the textLabel. I wouldn’t be surprised if it changes the font as well. This was the workaround I arrived at as well, but it seems like a bug.Rankins
There must be a better way to do this - layoutSubviews is supposed to only contain layout, it can be called several times in a single rendering loop, and as such, it's not recommended to place anything other than layout here; I assume the better approach is to either create a custom title label, or update the font in willDisplayHeaderView.Freezer
D
3

Seems like textLabel font is ignored even in iOS 11.

An alternative solution (Swift 4) is to use a custom label. It shouldn't be difficult if you already have a UITableViewHeaderFooterView subclass.

class MyTableViewHeader: UITableViewHeaderFooterView {
    let customLabel = UILabel()

    override init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        customLabel.frame = contentView.bounds
    }

    func setup() {
        customLabel.textColor = UIColor(white: 0.8, alpha: 1)
        customLabel.font = UIFont.systemFont(ofSize: 20)
        contentView.addSubview(customLabel)
    }
}
Dilantin answered 1/3, 2018 at 20:6 Comment(0)
F
0

Here is one a solution in Swift - the idea here is that we have a subclass of UITableViewHeaderFooterView called SNStockPickerTableHeaderView; it exposes a method called, configureTextLabel() that when called, sets the font and the color of the text label. We call this method only after the title has been set, that is from, willDisplayHeaderView, and the font gets correctly set.

// MARK: UITableViewDelegate

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

func tableView(tableView:UITableView, viewForHeaderInSection section:Int) -> UIView? {
  var headerView:SNStockPickerTableHeaderView? = tableView.dequeueReusableHeaderFooterViewWithIdentifier(kSNStockPickerTableHeaderViewReuseIdentifier) as? SNStockPickerTableHeaderView
  if (headerView == nil) {
    headerView = SNStockPickerTableHeaderView(backgroundColor:backgroundColor,
      textColor:primaryTextColor,
      lineSeparatorColor:primaryTextColor)
  }
  return headerView!
}

And here is the custom UITableViewHeaderFooterView:

import Foundation
import UIKit

private let kSNStockPickerTableHeaderViewLineSeparatorHeight:CGFloat = 0.5
private let kSNStockPickerTableHeaderViewTitleFont = UIFont(name:"HelveticaNeue-Light", size:12)

let kSNStockPickerTableHeaderViewReuseIdentifier:String = "stock_picker_table_view_header_reuse_identifier"

class SNStockPickerTableHeaderView: UITableViewHeaderFooterView {

  private var lineSeparatorView:UIView?
  private var textColor:UIColor?

  required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  // We must implement this, since the designated init of the parent class
  // calls this by default!
  override init(frame:CGRect) {
    super.init(frame:frame)
  }

  init(backgroundColor:UIColor, textColor:UIColor, lineSeparatorColor:UIColor) {
    super.init(reuseIdentifier:kSNStockPickerTableHeaderViewReuseIdentifier)
    contentView.backgroundColor = backgroundColor
    self.textColor = textColor
    addLineSeparator(textColor)
  }

  // MARK: Layout

  override func layoutSubviews() {
    super.layoutSubviews()
    let lineSeparatorViewY = CGRectGetHeight(self.bounds) - kSNStockPickerTableHeaderViewLineSeparatorHeight
    lineSeparatorView!.frame = CGRectMake(0,
      lineSeparatorViewY,
      CGRectGetWidth(self.bounds),
      kSNStockPickerTableHeaderViewLineSeparatorHeight)
  }

  // MARK: Public API

  func configureTextLabel() {
    textLabel.textColor = textColor
    textLabel.font = kSNStockPickerTableHeaderViewTitleFont
  }

  // MARK: Private

  func addLineSeparator(lineSeparatorColor:UIColor) {
    lineSeparatorView = UIView(frame:CGRectZero)
    lineSeparatorView!.backgroundColor = lineSeparatorColor
    contentView.addSubview(lineSeparatorView!)
  }
}

Here is the result, see section header for, "Popular Stocks":

                              enter image description here

Freezer answered 10/5, 2015 at 21:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.