Reload only one section header in UITableView

13,725

Solution 1

I'm a little unclear as to what's going on here, but it sounds like there is a UITableView concepts worth explaining here:

UITableView has its own concept of a cell, implemented as UITableViewCell, and its own concept of a header/footer, implemented as UITableViewHeaderFooterView.

Depending on which of these two you meant, there are a few things you can do to get the intended effect:

The UITableViewCell Approach:

If you're using a UITableViewCell as the first row of a section to act like a "header," and you just want to reload that row to the exclusion of the rest of the section, you can call yourTableViewInstance.reloadRows(at:with:) (Apple Documentation) This method takes an array of IndexPaths, and an animation style. You can pass in the indexPath of the one you want to reload.

The UITableViewHeaderFooterView Approach:

If you're using a proper UITableViewHeaderFooterView then you need to make sure that you're providing the appropriate view when reloading the section. Zack Shapiro outlines the steps you need to take in this answer:

  1. Create a class that's a subclass of UITableViewHeaderFooterView.
  2. Register it with your UITableView instance.
  3. Then in viewForHeaderInSection, you do let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderView") as! YourHeaderViewSubclass

The last thing he points out is this:

The deceptive thing is the function calls for a return of UIView? when it really needs a dequeuedReusableHeaderFooterView or reloadData will cause it to disappear.

It depends on which of these two implementation paths you're taking, but this should be enough information to point you in the right direction.

Edit:

Based on the code you added, it looks like you're calling yourTableViewInstance.dequeueReusableCell(withIdentifier:for:) instead of yourTableViewInstance.dequeueReusableHeaderFooterView(withIdentifier:) inside of viewForHeaderInSection.

You need to have a subclass of UITableViewHeaderFooterView and then call it correctly. Create that new subclass, then change this:

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

        let cellHeader = tableViewHome.dequeueReusableCell(withIdentifier: "header") as! HeaderTableViewCell

   // ...

to this:

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

        let cellHeader = tableViewHome.dequeueReusableHeaderFooterView(withIdentifier: "header") as! HeaderTableView

   // ...

You need to follow two steps here:

  1. Create a new class, subclassing UITableViewHeaderFooterView instead of UITableViewCell.
  2. Then use the appropriate class as outlined above.

Solution 2

Yes, It is.

Let's say that this is implementation of your method:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let customCell = .... as! YourCustomCell 
    customCell.someLabel.text = "Some Data"
    //... filling your curstom cell
    return customCell
}

You can change it in this way

func updateHeaderView(headerView:YourCustomCell, section: Int) {
    customCell.someLabel.text = "Some Data"
    //... filling your curstom cell  
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let customCell = .... as! YourCustomCell 
    self.updateHeaderView(customCell, section)
    return customCell
}

And call again self.updateHeaderView(customCell, section) whenever you want, e.g.

func buttonClicked() {
   let customCell = self.tableView.headerView(forSection: 0) as! YourCustomCell
   self.updateHeaderView(customCell, 0)
}

Solution 3

I think your header view class is extending UITableViewHeaderFooterView class. Add a function in the extension

extension UITableViewHeaderFooterView{
     func reloadHeaderCell(){
        preconditionFailure("This method must be overridden")
    }
}

Now override this in your Header class as below

class HeaderView: UITableViewHeaderFooterView {
   override func reloadHeaderCell() {
      ////// add your logic to reload view
    }
}

Now you can simply call below line to refresh views

self.tableView?.headerView(forSection:0)?.reloadHeaderCell()

Solution 4

What I did and working very correctly, Please follow the given answer:

SWIFT 3.1

Step 1:

Firstly I took a view xib, designed that according to my requirement and did register in my required class.

Secondly, did sub class class HeaderView: UITableViewHeaderFooterView of UITableViewHeaderFooterView

Like following image:

enter image description here

In my required class(here homeclass) I did register my xib file for my tableview.

override func viewDidLoad() {
        super.viewDidLoad()
        tableViewHome.register(UINib(nibName: "HeaderView", bundle: nil), forHeaderFooterViewReuseIdentifier: "HeaderView")
}

Step 2:

Then in my required class i did following:

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

        let cellHeader = tableViewHome.dequeueReusableHeaderFooterView(withIdentifier: "HeaderView") as! HeaderView
        cellHeader.filterAction(cellHeader.filter1Btn)


        return cellHeader
    }

And it started working as per my requirement, later i added custom delegate for more actions in my class, but by subviewing, its now working.

Share:
13,725

Related videos on Youtube

Abhishek Mitra
Author by

Abhishek Mitra

Updated on September 16, 2022

Comments

  • Abhishek Mitra
    Abhishek Mitra over 1 year

    I'm using a custom cell as a section header in my UITableView. In that cell there are three buttons. If any of the buttons are clicked in that section's cell, it should reload that custom section cell only, not any rows. Is this possible?

    I was using the following code to reload that cell:

    tableViewHome.reloadSections([1], with: UITableViewRowAnimation.none)
    

    It's hiding my section cell and distorting my entire table.

    UPDATE

    I'm using UITableView and following code I'm using:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    
            let cellHeader = tableViewHome.dequeueReusableCell(withIdentifier: "header") as! HeaderTableViewCell
    
            cellHeader.filter1btn.addTarget(self, action: #selector(filterBtnAction(_:)), for: .touchUpInside)
            cellHeader.filter2Btn.addTarget(self, action: #selector(filterBtnAction(_:)), for: .touchUpInside)
            cellHeader.filter3btn.addTarget(self, action: #selector(filterBtnAction(_:)), for: .touchUpInside)
    
    
            return cellHeader
        }
    
    
        @IBAction func filterBtnAction(_ sender: UIButton) {
    
            print(sender.tag)
    
            tableViewHome.reloadSections([1], with: UITableViewRowAnimation.none)
    
    
    
        }
    
  • Abhishek Mitra
    Abhishek Mitra almost 7 years
    I updated my question, kindly see once again. Thank you
  • Moshe
    Moshe almost 7 years
    Updated to reflect. Looks like you're mixing up the cell and the header/footer view. On the right track, but almost there!
  • Abhishek Mitra
    Abhishek Mitra almost 7 years
    Hello, Sorry for late replying, well, if i use yourTableViewInstance.dequeueReusableHeaderFooterView(withId‌​entifier:) then i can't access the buttons, if it is possible then any help will be appreciable. Thank you.
  • Abhishek Mitra
    Abhishek Mitra almost 7 years
    Thanks for your help, i made that. Thanks :)
  • Moshe
    Moshe almost 7 years
    Did you work out the issue with button interactivity?
  • Abhishek Mitra
    Abhishek Mitra almost 7 years
    Yes, I have used delegates for that, it is working perfectly now.
  • Tyler A.
    Tyler A. over 5 years
    I'm a bit confused here. It seems the answer matches doesn't match the question although it does match what the OP wants. Specifically, the question is how to reload a single/specific Header cell. The answer points out the "right" way of using UITableViewHeaderFooterView, but does not answer how to reload a single/specific header using that approach. I'm supposing the goal is to find reloadSectionIndexTitles() but for a single section. [Although Apple's documentation says "Reloads the items in the index bar along the right side of the table view." which is confusing.]
  • Dave
    Dave over 3 years
    This answer does not address the question even indirectly. As confusing as its acceptance by the OP is that individual's follow up answer claiming his own solution to the problem - which also doesn't solve the stated problem.