简体   繁体   中英

Cannot change text attributes of section header in UITableView

I'm pretty sure I've tried overriding every function that deals with a UITableViewHeaderFooterView to change the text, font, and textColor for the header in a tableView section.

I tried using this code found from another answer:

override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
    header.contentView.backgroundColor = UIColor(red: 0/255, green: 181/255, blue: 229/255, alpha: 1.0) 
    header.textLabel!.textColor = UIColor.whiteColor()
    header.alpha = 0.5 
    header.textLabel!.text = "foobar"
}

This successfully changed the background color of the header.contentView , however as soon as I add the line of code to change the text of the textLabel, nothing (including the background color) displays at all.

I am able to change the text with titleForHeaderInSection but the code in willDisplayHeaderView does nothing to effect the text attributes. Overriding viewForHeaderInSection also seems to do nothing. Someone please help!

Before trying to set anything there, make sure that the properties you are actually looking for have setters.

Issue

You are setting only the contentView because it can be set alongside with the tintColor , but the other properties are marked with get , so you can get the value but you don't have the permission to set it.

From Docs

 public var tintColor: UIColor! public var textLabel: UILabel? { get } public var detailTextLabel: UILabel? { get } // only supported for headers in grouped style public var contentView: UIView { get } public var backgroundView: UIView? public var reuseIdentifier: String? { get } 

Solution

There is a solution which can be achieved using UIAppearance Protocol

To customize the appearances for instances of a class when contained within an instance of a container class, or instances in a hierarchy, use appearanceWhenContainedIn: to get the appearance proxy for the class. For example, to modify the appearance of bar buttons, based on the object that contains the navigation bar:

Our case

UILabel.appearanceWhenContainedInInstancesOfClasses([UITableViewHeaderFooterView.self]).textColor = UIColor.whiteColor()

More Details

Solution 2

You can also create your own subclass of UIView and showing it under

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

This way you can modify whatever you want, rather than trying to customize something that is very limited at customization

This could possibly be a duplicate question, but after reading (a lot) of different solutions, none of them seemed to clarify an important piece of the puzzle when trying to resolve this issue and I think it will be constructive to shed some additional light on this problem.

TL;DR

Either use titleForHeaderInSection in conjunction with viewForHeaderInSection or create and return a UILabel in viewForHeaderInSection and set the height of the header in heightForHeaderInSection .

More thorough explanation

The Root of the Problem:
I was unable to change the text attributes because of an inappropriate use of willDisplayHeaderView . This is because this function should only be used after a UIView (or subclass of UIView) for the header has already been instantiated elsewhere. The header view does not get created unless done so through titleForHeaderInSection or viewForHeaderInSection .

Referring to titleForHeaderInSection From the docs:

Return Value
A string to use as the title of the section header. If you return nil , the section will have no title.

So, the million dollar question: Why couldn't I change the text in viewForHeaderInSection or willDisplayHeaderView unless I also set the text for a section header in titleForHeaderInSection ?
Turns out this is a trick question! Sort of.

In the case of using viewForHeaderInSection , the text actually is getting changed - you just can't see it. When you set the text of a section title with titleForHeaderInSection , swift automatically creates a UITableViewHeaderFooterView with a default height constraint for that particular section. Another option for creating a header view is to create and return a class of type UIView in viewForHeaderInSection , however the caveat here is that a default height constraint does not get created , thus you end up with a UIView container with a height of zero and it will not display onscreen - but this is easily remedied by giving it some height by overriding heightForHeaderInSection .

In the case of using willDisplayHeaderView , the problem existed as a result of incorrectly implementing that function. A header of class type UIView must be created either through returning a non-empty string value in titleForHeaderInSection or returning an object of class type UIView in viewForHeaderInSection before willDisplayHeaderView should be used. This is because the parameter named "view" in that function must already exist before you can change it's properties. Seems kind of like a no-brainer.

Solution 1

Simply make sure you return a non-empty string value from titleForHeaderInSection ; doing so will ensure that a header view object is instantiated. Use viewForHeaderInSection to set the properties of the header to your liking.

Solution 2

Override the function viewForHeaderInSection and create a new object that inherits from UIView (aka, UILabel, UITableViewHeaderFooterView, UIImageView, or whatever fits your fancy). Return that object, and then (very important!) set the height of the header in heightForHeaderInSection . There is no need to use titleForHeaderInSection with this approach.

There are several other solutions I was able to come up with, but these two are really the only ones that make any sense. And of course, if you are happy with the way your section headers look using Apple's default scheme, save yourself all the trouble and use titleForHeaderInSection exclusively.

I had the same issue and tried the answer by darksinge (solution 2). Still didn't work for me.

In my case, adding to solution2, I also need to change textLabel color(or some other elements of textLabel) at willDisplayHeaderView function. Seems internally object of UIlabel is overwritten before willDisplayHeaderView called.(assume if the object isKind of UIlabel, overwritten) Here's some complimentary explanation.

here's the code (SearchTableSectionHeaderFooterView is custom UITableViewHeaderFooterView class.)

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    return tableView.dequeueReusableHeaderFooterView(withIdentifier: SectionHeaderFooterIdentifier) as! SearchTableSectionHeaderFooterView
}

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    // header textLabel color should be modified here
    // ref) https://forums.developer.apple.com/thread/60735
    (view as! SearchTableSectionHeaderFooterView).textLabel?.textColor = UIColor.red
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return cells[section].title
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM