不使用tableView:titleForHeaderInSection更改UITableView部分标题

17

我试图在选中某个分组的单元格时,更改UITableView中该分组的标题。由于应用程序已触发tableView:titleForHeaderInSection,因此无法帮助解决此问题。我可以调用reloadData,但性能受到影响,因为应用程序必须重新加载所有可见单元格。我还尝试使用自定义标头,但这也会导致一些性能问题。

是否有任何方法获取默认标头视图使用的UILabel并手动更改其文本?

9个回答

24

调用[tableView endUpdates]可能会在不牺牲太多性能的情况下提供所需的结果。

[self.tableView beginUpdates];
[self.tableView endUpdates];

// forces the tableView to ask its delegate/datasource the following:
//   numberOfSectionsInTableView:
//   tableView:titleForHeaderInSection:
//   tableView:titleForFooterInSection:
//   tableView:viewForHeaderInSection:
//   tableView:viewForFooterInSection:
//   tableView:heightForHeaderInSection:
//   tableView:heightForFooterInSection:
//   tableView:numberOfRowsInSection:

3
在iOS10/11(使用Swift语言),我注意到tableView:viewForHeaderInSection:tableView:viewForFooterInSection:没有被调用,因此您需要自己更改视图。 - Casper Zandbergen

17

使用:

[self.tableView headerViewForSection:i]

你可以获取第i部分的视图,然后手动“更新”它。即使你的视图只是自动生成的标签,这也适用,但你需要自己调整大小。所以如果你尝试:
[self.tableView headerViewForSection:i].textLabel.text = [self tableView:self.tableView titleForHeaderInSection:i];

您将设置文本,但不会设置标签大小。您可以从NSString中获取所需的大小并自行设置:

[label.text sizeWithFont:label.font];

这种方法有些不专业,不建议使用,但确实能够满足原问题的要求。所以点个赞。 - bioffe
2
[self.tableView headerViewForSection:i] 总是返回 nil 值。 - Mehul Thakkar
2
如果headerViewForSection返回nil,则表示标题视图不可见。对于动态表格,它可以正常工作。 - pronebird
我找到的唯一可行的解决方案是:sizeWithFont已经被弃用了。作为替代,您可以将标签的框架宽度设置为其父视图的宽度。 - Sergey M
@BijoyThangaraj 那显然是你实现的方法。标题文本内容来自哪里并不重要。你可以用一些常量字符串替换它。 - Dr. Azrael Tod
显示剩余2条评论

15

目前似乎没有任何标准API用于访问系统提供的节头视图。你尝试过更有针对性的reloadSections:withRowAnimation来让UIKit显示新的节头文本吗?

你在使用自定义部分标题视图时遇到了什么样的性能问题?我怀疑标准标题视图仅仅是一个UILabel而已。


看起来我可能不得不使用reloadSections,即使它几乎和重新加载整个表格一样慢(至少对于我的应用程序来说)。 Cocoa API已经让我无从下手。我尝试使用循环队列来重复使用一组UILabel,并在viewForHeader中返回它们,但是viewForHeader被调用了这么多次(甚至是那些不可见的单元格!),以至于我需要为每个单元格创建一个单独的UILabel,这就是明摆着的坏事。唉! - mathew

4
您可以直接为部分标题标签设置标题。例如,要设置第零部分的标题:
UITableViewHeaderFooterView *sectionZeroHeader = [self.tableView headerViewForSection:0];
NSString *sectionZeroLabel = @"Section Zero";
[sectionZeroHeader.textLabel setText:[sectionZeroLabel uppercaseString]];
[sectionZeroHeader setNeedsLayout];

请务必告诉节标题视图需要布局,否则新文本可能会被截断。此外,部分标签通常都是大写字母。


如果您正在使用自动高度,这似乎无法正常工作。 - lostintranslation

1

由于UITableView不会对节头视图进行排队和出列以供重用,因此您可以考虑将所有节头视图存储在内存中。请注意,您将需要创建自己的带有背景等的节头视图来实现此目的,但这样做可以为您提供更多的灵活性和功能。

您还可以尝试标记节头视图(也需要您创建自己的节头视图),并根据需要从表格视图中获取它们。


0
如果您想要更新某个部分,最好的方法是使用tableView.headerView。如果表头不可见,则返回nil,因此不会加载额外的表头。
if let header = tableView.headerView(forSection: i) {
    header.textLabel!.text = "new title"
    header.setNeedLayout()
}

如果您想要更新所有可见的章节标题,最好在显示视图之前将标题标签设置为“section”,并在需要时枚举子视图:
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
    view.tag = section
    // additional customization
}

func udpateVisibleSectionHeaders() {
    for subview in tableView.subviews {
        if let header = subview as? UITableViewHeaderFooterView {
            let section = header.tag
            header.textLabel!.text = "new title"
            header.setNeedsLayout()
        }
    }
}

不要忘记调用setNeedsLayout,否则标签可能会被截断。

0
这只是个猜测,我可以想到很多原因可能导致它无法工作,但你不能通过遍历子视图来找到你要找的那一个吗?例如:
for (UIView *v in self.tableView.subviews) {
    // ... is this the one?
}

0

其中一种解决方案是管理外部数组,用于包含标签引用的多个部分标题,并在外部更新它们。


0

为了完整性,我们都在寻找的方法是这个私有API,它的名称正是你所期望的:

-(void)_reloadSectionHeaderFooters:withRowAnimation:

例如:

[tableView _reloadSectionHeaderFooters:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationAutomatic]

然而,我不建议使用这个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接