Reputation: 16246
This one is driving me crazy.
UITableViewController
.UITableViewController
is both the delgate and the data source of its table view).tableView(_:titleForHeaderInSection:)
The view controller (the delegate) implements:
tableView(_:viewforHeaderInSection:)
tableView(_:heightForHeaderInSection:)
tableView(_:estimatedHeightForHeaderInSection)
...neither of which is ever called.
As a result, my table view sections do not display any header.
If I specify the table view's global section header height:
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedSectionHeaderHeight = 12 // (say)
...then blank headers are displayed, but tableView(_:titleForHeaderInSection:)
et al are still not called and my custom header views never get displayed.
Similar questions have been asked before, and Apple's docs seems to not be 100% correct, however I am positive that I am doing everything that is required (I have tried all configurations).
What am I missing?
The codebase is large, and not mine; perhaps I am missing something somwehere but don't know what else to look for...
Update
I created a new, minimal project to test and it turns out I only need to implement these two delegate methods (and not modify any properties of the table view):
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) // (say)
view.backgroundColor = UIColor.red // (say)
return view
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 10.0 // (say)
}
...to have my custom section header view displayed.
However, the same setup does not work on my existing project. Something, somewhere must be interfering...
Update 2
I sublcassed UITableView
to see what was going on, but still can't figure it out (see inline comments):
import UIKit
class DebugTableView: UITableView {
// GETS EXECUTED:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override var estimatedSectionHeaderHeight: CGFloat {
// NEVER GETS EXECUTED:
get {
return super.estimatedSectionHeaderHeight
}
// NEVER GETS EXECUTED:
set (newValue) {
super.estimatedSectionHeaderHeight = newValue
}
}
override var sectionHeaderHeight: CGFloat {
// NEVER GETS EXECUTED:
get {
return super.sectionHeaderHeight
}
// NEVER GETS EXECUTED:
set (newValue) {
super.sectionHeaderHeight = newValue
}
}
// NEVER GETS EXECUTED:
override func headerView(forSection section: Int) -> UITableViewHeaderFooterView? {
let view = super.headerView(forSection: section)
return view
}
// GETS EXECUTED ONCE PER CELL:
override func rectForHeader(inSection section: Int) -> CGRect {
var rect = super.rectForHeader(inSection: section)
rect.size.height = 1000 // HAS NO EFFECT
return rect
}
}
Upvotes: 1
Views: 2580
Reputation: 27428
You just need to set sectionHeaderHeight
also, not only estimated height!
like,
Swift 4.0
tableView.sectionHeaderHeight = UITableView.automaticDimension
tableView.estimatedSectionHeaderHeight = 25
and then just override viewForHeaderInSection
. and no need to override any other delegates!
Upvotes: 2
Reputation: 16246
I found the problem.
It turns out there was an auxiliary object overtaking the role of table view delegate and hiding it.
This class:
UITableViewDelegate
protocol and implements most of its methods (but not the header/footer-related ones), viewDidAppear()
method,When it's implementation of (say) tableView(_:didSelectRowAtIndexPath:) is called, it in turn calls the table view controller's equivalent method, giving the impression that the view controller is still the delegate:
class ManInTheMiddle: NSObject, UITableViewDelegate {
var formerDelegate: UITableViewController?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
formerDelegate?.tableView(tableView, didSelectRowAt: indexPath)
// Do some other stuff...
}
}
This is why some methods of UITableViewDelegate
where being called on my table view controller and some weren't.
I discovered this by overriding the table view's delegate
property:
class DebugTableView: UITableView {
// ...
override var delegate: UITableViewDelegate? {
get {
return super.delegate
}
set (newValue) {
super.delegate = newValue // < BREAKPOINT HERE
}
}
...out of desperation (there was no strong reason to suspect the delegate was swapped, being that most methods worked...)
<rant>Damn, do I hate these kind of dirty hacks... This is almost #define true false
territory, sheesh...
</rant>
Upvotes: 1