1

I need my tableView to fire an event for:

override func tableView(_ tableView: UITableView, didEndDisplayingFooterView view: UIView, forSection section: Int)

to do that, according to the documentation, I can't just add a view to the tableView like this:

tableView.tableFooterView = spaceView

which, whilst working, doesn't make that function get fired, nor does the table dequeue the footer despite how long the table might get.

I can't do this in the storyboard / XIB because whether a footer is added or not, is a decision only made at runtime.

So according to the documentation or at least my understanding of them, I have to make 'spaceView' a subclass of UITableViewHeaderFooterView and I have to do a formal 'register' to add it into the tableView, like this:

let spaceView = UITableViewHeaderFooterView(reuseIdentifier: "emptyFooter")

tableView.register(spaceView, forHeaderFooterViewReuseIdentifier: "emptyFooter")

But then I get a compile error:

Cannot invoke 'register' with an argument list of type '(UITableViewHeaderFooterView, forHeaderFooterViewReuseIdentifier: String)'

So, despite the docs, any ideas how I'm reading the doc's wrong?

Elphaba
  • 89
  • 1
  • 9
  • 1
    https://stackoverflow.com/questions/36926612/swift-how-creating-custom-viewforheaderinsection-using-a-xib-file – Mitesh jadav Jun 30 '18 at 12:53
  • Nope. Yet again, as I said, no XIB, and no method returning a default FOOTER VIEW as in your suggestion below. – Elphaba Jun 30 '18 at 13:01
  • Wait. Do you **one** footer at the bottom of the table view? Or do you want **one footer per section**? – André Slotta Jun 30 '18 at 13:08
  • One at the end of the entire table - there will be only one section. – Elphaba Jun 30 '18 at 13:09
  • In that case you have to go with `tableView.tableFooterView = yourFooterView`. The `didEndDisplayingFooterView` delegate function only gets called for section footers. What are you trying to achieve with that function? – André Slotta Jun 30 '18 at 13:11
  • As I said at the beginning of my question, I did that, but I need that function to get called. Because the app has 1 section, because it has too, that method I need firing should still get called. According to the docs, it won't get called unless the FOOTER VIEW has been added correctly - with a 'register' command. – Elphaba Jun 30 '18 at 13:13
  • @AndréSlotta What I'm trying to achieve, is knowing when the footer is no longer visible on screen and then removing it manually. – Elphaba Jun 30 '18 at 13:14

3 Answers3

4

The correct answer to your question is:

class CustomTableViewHeaderFooterView: UITableViewHeaderFooterView { }

class CustomTableViewController: UITableViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(CustomTableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "CustomTableViewHeaderFooterView")
    }
}

Then you can use the registered header / footer view like this:

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

override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
    let customFooterView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "CustomTableViewHeaderFooterView")
    // set up your footer view
    return customFooterView
}

To achieve what you explained in your comments though you do not have to register any UITableViewHeaderFooterView. Instead you can use the table view's tableFooterView and implement the functionality yourself. Try this inside your UITableViewController class:

override func viewDidLoad() {
    super.viewDidLoad()

    let footerView = UIView()
    footerView.backgroundColor = .orange
    footerView.frame.size.height = 44

    tableView.tableFooterView = footerView
}

var footerViewIsVisible = false {
    didSet {
        if !footerViewIsVisible && oldValue {
            tableViewDidEndDisplayingTableFooterView(tableView)
        }
    }
}

func tableViewDidEndDisplayingTableFooterView(_ tableView: UITableView) {
    print("didEndDisplayingTableFooterView")
    tableView.tableFooterView = nil
}

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if let tableFooterView = tableView.tableFooterView {
        let visibleRect = CGRect(origin: scrollView.contentOffset, size: scrollView.bounds.size)
        self.footerViewIsVisible = visibleRect.intersects(tableFooterView.frame)
    }
}
André Slotta
  • 13,774
  • 2
  • 22
  • 34
0

you can do like this:

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 45
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 60))
    headerView.backgroundColor = UIColor(red: 30/255, green: 30/255, blue: 32/255, alpha: 1.0)
    return headerView
}
Mitesh jadav
  • 910
  • 1
  • 9
  • 26
  • thanks for helping but that doesn't work for me. I need to have or not have a FOOTER depending on other code and tests that occur in other functions. It's not a global - always return this view sort of problem. – Elphaba Jun 30 '18 at 12:55
0

Thanks for the suggestions, but none of these either addressed the problem, or led to a solution.

Instead, I have the functionality, exactly as I wanted it, with just a small function of 6 lines of code and one private property on the view controller.

As soon as the tableView.footerView goes 'offscreen' it's instantly set to nil, and it's only created exactly when I want it to be.

Elphaba
  • 89
  • 1
  • 9