Using Swift 3, I'm trying to change the Section's Header color programmatically.
How do I change the backgroundColor to white and Text Color to black?
The sections header changes color but no text appears and then when I add code to change the header text color it crashes
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: 'Can't add self as subview'
Swift Code
// Title for Header
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
// Section Names
let sectionNames = ["Followed Blogs", "All Blogs"]
return sectionNames[section]
}
// View for Header
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
let headerLabel = UILabel()
let sectionNames = ["Followed Blogs", "All Blogs"]
headerLabel.text = sectionNames[section]
headerLabel.frame = CGRect(x: 45, y: 5, width: 100, height: 35)
headerLabel.addSubview(headerLabel)
if (section == 0) {
headerView.backgroundColor = UIColor.green
headerLabel.textColor = UIColor.black
} else {
if darkMode {
headerView.backgroundColor = UIColor.white
headerLabel.textColor = UIColor.black
} else {
headerView.backgroundColor = UIColor.black
headerLabel.textColor = UIColor.white
}
}
return headerView
}
// Height for Section
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
headerLabel.addSubview(headerLabel) is adding the label to self, which is the source of your error
Based on my understanding of your code, you should probably be using headerView.addSubview(headerLabel) instead
The text "Followed Blogs" doesn't fit it shows as "Followed B..."
This is (most likely) a layout issue, I'd personally investigate adding auto layout constraints to the label so that it binds to the top/bottom/left/right margins of the parent view
This is just to add on MadProgrammer's answer. I think instead of UIView you should use UITableViewHeaderFooterView
usage:
tableViewInstance.register(UITableViewHeaderFooterView.self, forHeaderFooterViewResuseIdentifier: "headerIdentifier")
Then in viewForHeaderInSection:
let tableViewHeader = tableview.dequeueReusableHeaderFooterView(withIdentifier: "headerIdentifier")
btw, regarding the text "Followed Blogs" not fitting in its because of your label's width is too small for the current font. Why not add a constraints like this:
headerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-5-[label]-5-|",
options: [],
metrics: nil,
views: ["tableView": headerLabel]))
headerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-5-[label]-5-|",
options: [],
metrics: nil,
views: ["tableView": headerLabel]))
You make your tableView's headerHeight be dynamic
Related
How do I go about dynamically changing the UITableViewCell height? I've tried implementing the following, but for some reason, it isn't working. The code crashes as soon as I load the view controller displaying this table view
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell
return cell.getHeight()
}
This is the getHeight function in my AvailableRideCell
func getHeight() -> CGFloat {
return self.destinationLabel.optimalHeight + 8 + self.originLabel.optimalHeight + 8 + self.priceLabel.optimalHeight
}
And this is the optimalHeight function
extension UILabel {
var optimalHeight : CGFloat {
get {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = self.font
label.text = self.text
label.sizeToFit()
return label.frame.height
}
}
}
Keep in mind that UITableViewCell is reused. So getting the height of the current cell can be unstable.
A better way is to have one fake/placeholder cell (I call the calculator cell) and use that to calculate the size of the cell.
So in the heightForRowAt method, you get the data instead of the cell.
Put that data inside the calculator cell and get the height from there.
You code crashes because of this line
let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell
From Apple Documentation we know that this method is used for optimization. The whole idea is to get cells heights without wasting time to create the cells itself. So this method called before initializing any cell, and tableView.cellForRow(at: indexPath) returns nil. Because there are no any cells yet. But you're making force unwrapping with as! AvailableRideCell and your code crashed.
So at first, you need to understand, why you should not use any cells inside the cellForRow(at ) method.
After that, you need to change the logic so you could compute content height without calling a cell.
For example, in my projects, I've used this solution
String implementation
extension String {
func height(for width: CGFloat, font: UIFont) -> CGFloat {
let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
let actualSize = self.boundingRect(with: maxSize,
options: [.usesLineFragmentOrigin],
attributes: [NSAttributedStringKey.font: font],
context: nil)
return actualSize.height
}
}
UILabel implementation
extension String {
func height(for width: CGFloat, font: UIFont) -> CGFloat {
let labelFrame = CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude)
let label = UILabel(frame: labelFrame)
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.font = font
label.text = self
label.sizeToFit()
return label.frame.height
}
}
With that, all you need to do is to compute your label and store its font.
var titles = ["dog", "cat", "cow"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// number of rows is equal to the count of elements in array
return titles.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cellTitle = titles[indexPath.row]
return cellTitle.height(forWidth: labelWidth, font: labelFont)
}
Dynamic rows height changing
If you'll need to update row height, all you need to do is to call this method when your content had been changed. indexPath is the index path of changed item.
tableView.reloadRows(at: [indexPath], with: .automatic)
Hope it helps you.
You don't mention if you are using Auto Layout, but if you are, you can let Auto Layout manage the height of each row. You don't need to implement heightForRow, instead set:
tableView.rowHeight = UITableViewAutomaticDimension
And configure your UILabel with constraints that pin it to the cell's content view:
let margins = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
cellLabel.leadingAnchor.constraint(equalTo: margins.leadingAnchor),
cellLabel.trailingAnchor.constraint(equalTo: margins.trailingAnchor),
cellLabel.topAnchor.constraint(equalTo: margins.topAnchor),
cellLabel.bottomAnchor.constraint(equalTo: margins.bottomAnchor)
])
Each row will expand or contract to fit the label's intrinsic content size. The height is automatically adjusted if the device landscape/portrait orientation changes, without re-loading the cell. If you want the row height to change automatically when the device's UIContentSizeCategory changes, set the following:
cellLabel.adjustsFontForContentSizeCategory = true
I am implementing a view that displays a lot of information. The view is scrollable and inside of the view I implemented a non-scrollable table view holding user comments. I have all the auto-layout constraints and it appears to layout correctly however touches are not received below a certain row. It appears that the table view or something is blocking the views below from receiving the events but I am unable to trace down the issue.
I want the main scroll view's content size to grow as the comment table view grows. Keeping the post comment view at the bottom of the table view. Right now I can't select the last cell or the text field.
Comment Cell View
Simulator screenshot
Here is the code from the table view implementation:
commentsTableView.delegate = self
commentsTableView.dataSource = self
commentsTableView.estimatedRowHeight = 82
commentsTableView.rowHeight = UITableViewAutomaticDimension
commentsTableView.sectionHeaderHeight = UITableViewAutomaticDimension
commentsTableView.estimatedSectionHeaderHeight = 54
commentsTableView.estimatedSectionFooterHeight = 0
commentsTableView.sectionHeaderHeight = UITableViewAutomaticDimension
commentsTableView.tableFooterView = UIView(frame: CGRectZero)
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Comments"
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section != 0 { return nil }
let sectionTitle: String = self.tableView(tableView, titleForHeaderInSection: section)!
if sectionTitle == "" {
return nil
}
let view = UIView(frame: CGRectMake(0, 0, tableView.frame.width, 54))
let title = UILabel(frame: CGRectMake(60, 22, tableView.frame.width, 17))
view.addSubview(title)
title.text = sectionTitle
title.textColor = UIColor(red: (74 / 255), green: (74 / 255), blue: (74 / 255), alpha: 1.0)
title.backgroundColor = UIColor.clearColor()
view.backgroundColor = UIColor.clearColor()
title.font = UIFont(name: "ProximaNova-Semibold", size: 16.0)
view.layer.addBorder(.Bottom, color: UIColor.lightGrayColor().colorWithAlphaComponent(0.75), thickness: 0.5)
title.setNeedsDisplay()
view.setNeedsDisplay()
return view
}
You have to set the userInteractionEnabled to true to fire those events.
view.userInteractionEnabled = true
The Comment TextField is the last row of your comment TableView. So put comment TextField code in footer of the TableView as follows:
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let commentTextFieldView = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 50))
// Your Comment TextField code
return commentTextFieldView
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 50.0
}
There is an another way to assign Comment TextField view as tableView footer:
myTableView.tableFooterView = commentTextFieldView
I changed a tableView from Plain to Grouped so that the header/footer does not float over the table and stays anchored to the top and bottom of the table. That was straightforward, but now the font style formatting that I setup is not working. Strangely all other formatting of the header/footer seems to be working though. Any thoughts on what is going and what I am missing are appreciated!
Code below:
// Setup format of the header
func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let title = UILabel()
title.font = UIFont(name: "Avenir Book", size: 12)
title.textColor = UIColor.whiteColor()
let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
header.contentView.backgroundColor = UIColor(red: 30/255, green: 30/255, blue: 50/255, alpha: 1)
header.textLabel!.font = title.font
header.textLabel?.textColor = title.textColor
header.textLabel?.numberOfLines = 0
header.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
header.textLabel?.textAlignment = NSTextAlignment.Center
}
In a Plain table all of the above works great and looks like this:
However, when I change to Grouped table all of the formatting seems to show up except for the font style this this:
I am puzzled about where the ALL CAPS is coming from.
I tried to implement the solution from this question/answer, but could not get it to work either. Thanks for your ideas!
Assuming that you provided the string for the section title in this method:
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
But in a grouped tableview, that string is changed to all caps. To remove the all caps, try adding one of these two lines in the willDisplayHeaderView method:
header.textLabel?.text = header.textLabel!.text!.capitalizedString
header.textLabel?.text = header.textLabel!.text!.lowercaseString
The first one will capitalize the first letter of every word and the second will make everything lowercase. If you don't want either of those you could add the string directly:
header.textLabel?.text = "Here are a few options for you. Select to learn more"
Swift 4
use this delegates:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let label: UILabel = {
let label = UILabel()
label.textAlignment = .right
label.textColor = .white
label.backgroundColor = .clear
label.font = UIFont.systemFont(ofSize: 20)
return label
}()
return label
}
and don't forget to set height for header:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 70
}
hope this help.
Update for >=iOS 14, with the UIListContentConfiguration API:
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
guard let headerView = view as? UITableViewHeaderFooterView else {
return
}
var config = headerView.defaultContentConfiguration()
// This needs to explicitly be set if the table view is Grouped style
// (which it is, to hide sticky backgrounds on section headers),
// as the deafult style for
config.textProperties.transform = .none
// Other properties (color, font) as needed...
// Notably, `ContentConfiguration` requires setting content here as well,
// separate from `titleForHeaderInSection`
config.text = "MyText"
headerView.contentConfiguration = config
headerView.setNeedsUpdateConfiguration()
}
This question already has answers here:
How to customise header section in static cell?
(3 answers)
Closed 6 years ago.
I have this UITableView with static cells:
I'd like to change the header field and center horizontally in the cell. How can I do using Swift?
Thanks in advance.
first of all, of course you can do this using swift, and now this is the code that you need to put in your viewController to make this work
you need to put your viewController as UITableViewDelegate and then implement this methods
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return X; //X is the value of height of your header
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.frame.size.width, height: X)) //X is the value of height of your header
let label = UILabel(frame: headerView.frame)
label.text = "TESTING"
label.textAlignment = NSTextAlignment.Center
headerView.addSubview(label)
return headerView;
}
I hope this help you
Sounds like you are wanting to use:
tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
}
Using this you could code the UI you are looking for, create the label and set the frame to what you need and set the text to what you would want it to be. Inside would either if check or use a switch statement for section, and set the text accordingly, then simply return the label or view, however you decide to implement your solution. I have done something like this in a tableView footer, I'll post the code and link to the documentation for reference:
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView.init(frame: CGRectMake(0, 0, tableView.frame.size.width, 50))
//label
let label : UILabel = UILabel.init(frame: CGRectMake(30, 0, 150, 50))
label.text = "Calorie Total :"
//label to hold calorie total for the section
let totalLabel = UILabel.init(frame: CGRectMake(185, 0, 50, 50))
var total = Int()
//grab the total for the section
switch section {
case 0:
total = calculateCalories(breakfastFoodArray)
break
case 1:
total = calculateCalories(lunchFoodArray)
break
case 2:
total = calculateCalories(dinnerFoodArray)
break
case 3:
total = calculateCalories(snackFoodArray)
break
default:
break
}
totalLabel.text = String(total)
footerView.addSubview(label)
footerView.addSubview(totalLabel)
let footerExentsionView = UIView.init(frame: CGRectMake(0, 50, tableView.frame.size.width, 10))
footerExentsionView.backgroundColor = UIColor.whiteColor()
footerView.addSubview(footerExentsionView)
return footerView
}
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.
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
}
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
}
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.
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
}
}
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)
}
}
Swift 2.0:
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
}
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!
}
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
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;
}
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
}
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)
}
}
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}
}