在 UITableView 中仅重新加载一个节标题

Posted

技术标签:

【中文标题】在 UITableView 中仅重新加载一个节标题【英文标题】:Reload only one section header in UITableView 【发布时间】:2017-07-03 14:12:05 【问题描述】:

我在UITableView 中使用自定义单元格作为部分标题。在那个单元格中有三个按钮。如果在该部分的单元格中单击任何按钮,它应该只重新加载该自定义部分单元格,而不是任何行。这可能吗?

我正在使用以下代码重新加载该单元格:

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

它隐藏了我的部分单元格并扭曲了我的整个表格。

更新

我正在使用UITableView 以及我正在使用的以下代码:

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)



    

【问题讨论】:

【参考方案1】:

我有点不清楚这里发生了什么,但听起来这里有一个UITableView 概念值得解释:

UITableView 有自己的单元格概念,实现为UITableViewCell,以及自己的页眉/页脚概念,实现为UITableViewHeaderFooterView

根据您的意思是这两个中的哪一个,您可以做一些事情来获得预期的效果:

UITableViewCell 方法:

如果您使用 UITableViewCell 作为部分的第一行以充当“标题”,并且您只想重新加载该行以排除该部分的其余部分,您可以调用 @987654334 @(Apple Documentation) 这个方法接受一个IndexPaths 的数组和一个动画样式。您可以传入要重新加载的那个的 indexPath。

UITableViewHeaderFooterView 方法:

如果您使用的是正确的UITableViewHeaderFooterView,那么您需要确保在重新加载该部分时提供了正确的视图。 Zack Shapiro 概述了您在this answer 中需要采取的步骤:

    创建一个作为UITableViewHeaderFooterView 子类的类。 用您的UITableView 实例注册它。 然后在viewForHeaderInSection,你做let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderView") as! YourHeaderViewSubclass

他最后指出的是:

具有欺骗性的是,当它确实需要 dequeuedReusableHeaderFooterViewreloadData 时,函数调用返回 UIView? 会导致它消失。

这取决于您采用这两种实现路径中的哪一种,但这应该足以为您指明正确的方向。

编辑:

根据您添加的代码,您似乎是在 viewForHeaderInSection 内部调用 yourTableViewInstance.dequeueReusableCell(withIdentifier:for:) 而不是 yourTableViewInstance.dequeueReusableHeaderFooterView(withIdentifier:)

您需要有UITableViewHeaderFooterView 的子类,然后正确调用它。创建新的子类,然后更改:

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

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

   // ...

到这里:

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

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

   // ...

您需要在此处执行两个步骤:

    创建一个新类,继承 UITableViewHeaderFooterView 而不是 UITableViewCell。 然后使用上述适当的类。

【讨论】:

我更新了我的问题,请再次查看。谢谢 已更新以反映。看起来您正在混淆单元格和页眉/页脚视图。在正确的轨道上,但几乎就在那里! 您好,很抱歉回复晚了,好吧,如果我使用yourTableViewInstance.dequeueReusableHeaderFooterView(withIdentifier:),那么我将无法访问按钮,如果可能的话,任何帮助都将是可观的。谢谢。 感谢您的帮助,我做到了。谢谢:) 我在这里有点困惑。似乎答案匹配与问题不匹配,尽管它确实符合 OP 的要求。具体来说,问题是如何重新加载单个/特定的 Header 单元格。答案指出了使用UITableViewHeaderFooterView 的“正确”方式,但没有回答如何使用该方法重新加载单个/特定标头。我假设目标是找到reloadSectionIndexTitles(),但只针对单个部分。 [尽管 Apple 的文档说“重新加载表格视图右侧索引栏中的项目”。这令人困惑。]【参考方案2】:

是的,是的。

假设这是你的方法的实现:

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

你可以这样改

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

然后随时再次致电self.updateHeaderView(customCell, section),例如

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

【讨论】:

let customCell = tableViewHome.headerView(forSection: 0) as! HeaderTableViewCell 中写着Cast from 'UITableViewHeaderFooterView?' to unrelated type 'HeaderTableViewCell' always fails【参考方案3】:

我认为您的标题视图类正在扩展 UITableViewHeaderFooterView 类。在扩展中添加一个函数

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

现在在您的 Header 类中覆盖它,如下所示

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

现在您可以简单地调用下面的行来刷新视图

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

【讨论】:

【参考方案4】:

我做了什么并且工作非常正确,请按照给定的答案:

SWIFT 3.1

第 1 步:

首先我拿了一个view xib,根据我的要求设计了它,并在我要求的课程中注册了。

其次,做了UITableViewHeaderFooterView的子类class HeaderView: UITableViewHeaderFooterView

如下图:

在我的必修课(这里是 homeclass)中,我确实为我的 tableview 注册了我的 xib 文件。

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

第 2 步:

然后在我的必修课中,我做了以下操作:

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

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


        return cellHeader
    

它开始按照我的要求工作,后来我为我的班级中的更多动作添加了自定义委托,但是通过子视图,它现在可以工作了。

【讨论】:

以上是关于在 UITableView 中仅重新加载一个节标题的主要内容,如果未能解决你的问题,请参考以下文章

重新加载节而不重新加载节标题

重新加载 UITableView 而不重新加载 Section Header

重新加载节索引时出现奇怪的错误?

刷新 UITableView tableFooterView 而不重新加载整个表数据

重新加载 UITableView 而不重新加载标题部分

在 UITableView 中的 UINib 中重新加载 UITableView