UITableView页眉页脚视图的内容选择行时视图大小意外更改



当我选择一行时,UITableView中的节标题会改变大小,从而使表的节在点击一行时会跳跃。

该应用程序正在使用具有动态大小的自定义字体。我正在用设置字体

UIFontMetrics(forTextStyle: <textStyle>).scaledFont(for: <font>, maximumPointSize: <maximumPointSize>)

我有一种方法可以解决默认设置的问题,但问题会返回到大的可访问性字体大小。

该表由两部分组成。章节标题使用标准组件。第一部分(通常包含三个单元格)使用标准的UITableViewCell。第二部分有一个自定义单元格,选中后插入第二个带有选择器的自定义单元格(cf开始时间单元格在iOS日历应用程序中打开日期选择器的方式)。使用带有insertRows的beginUpdates/endUpdates块插入额外的单元格。

发生的情况是:当第一次呈现表时,标题的contentView比带有标题的UILabel大得多。如果我点击第2节中打开第二个单元格的单元格,则标题contentView的大小将减小,以匹配标签的大小。除非我选择第一节中的一个单元格,否则它将保持这种状态。此时,标题再次调整大小,现在的contentSize比原来的小,但比最小时大。

以下是我尝试过的:

我最初使用指定了表格标题的字体大小

UILabel.appearance(whenContainedInInstancesOf: [UITableViewHeaderFooterView.self])

在AppDelegate中,这是我处理其他类型组件的地方。然而,在重新加载表数据时,UITableView似乎没有系统地观察到这一点,即在重新加载表格期间,字体大小本身会发生变化(而不仅仅是contentView大小)。

我更改了代码,改为在willDisplayHeaderView中指定字体大小,例如:

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
if let header = view as? UITableViewHeaderFooterView {
if let textlabel = header.textLabel {
textlabel.font = UIFontMetrics(forTextStyle: .body).scaledFont(for:Theme.font, maximumPointSize: 30)
}
if section == 0 {
header.accessibilityLabel = ...
header.accessibilityHint = ...
} else {
header.accessibilityLabel = ... 
header.accessibilityHint = ... 
}

这消除了重新绘制表格时字体大小发生变化的问题。它还解决了标题的contentView大小更改为默认字体大小的问题。但是,一旦我在辅助功能设置中切换了字体大小,就会出现标题contentView大小更改问题。

我已尝试设置Section HeaderHeight("settings"是UITableView)

self.settings.sectionHeaderHeight = UITableView.automaticDimension
self.settings.estimatedSectionHeaderHeight = 60

这也没什么区别。

如果我猜测的话,看起来标题有时会根据显示更大的UILabel来调整大小,但为什么大小会根据表的重新绘制方式而不同呢?

我想下一步是用自定义视图替换表标题,但这似乎有些过头了。

我错过了什么?

如果不添加自定义头,我就无法让它工作,所以这就是我使用的解决方案。自定义标头使用了一个相当丑陋的解决方法来控制标头的高度。

我最初的实现有这样的组合:

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "One"
} else if section == 1 {
return "Two"
} else {
// Should not happen
return "Other"
}
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
if let header = view as? UITableViewHeaderFooterView, let textlabel = header.textLabel {
textlabel.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: ..., maximumPointSize: 23)
}   
}

以下是解决方法。

  1. 注册自定义标头
<UITableView>.register(TableHeaderView.self, forHeaderFooterViewReuseIdentifier: "Header")
  1. 带有控制大小的不可见标签的"自定义"标头
class TableHeaderView: UITableViewHeaderFooterView {
// Dummy invisible label that controls the size of the header
let label = UILabel()
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
self.label.text = "M"
self.label.textColor = UIColor.white.withAlphaComponent(0)
// Make sure VoiceOver doesn't see it
self.label.isAccessibilityElement = false
// Set the font 
self.label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: ..., maximumPointSize: 23)
self.label.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.label)
let size = self.label.sizeThatFits(CGSize.zero)
NSLayoutConstraint.activate([
self.contentView.heightAnchor.constraint(equalToConstant: size.height + 20),
self.label.centerYAnchor.constraint(equalTo: self.contentView.centerYAnchor, constant: 20),
self.label.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 12.0)])
self.label.text = " "
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
  1. 使用viewForHeaderInSection加载自定义标头
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "Header") as? TableHeaderView {
if section == 0 {
header.textLabel?.text = "One"
} else if section == 1 {
header.textLabel?.text = "Two"
} else {
// Should not happen
header.textLabel?.text = "Other"
}
return header
}
return nil
}

最新更新