是否可以使用自动布局获得动态 table 视图部分 header 高度?

Is it possible to obtain a dynamic table view section header height using Auto Layout?

iOS8 中的新增功能,您只需设置估计的行高即可获得 100% 动态 table 视图单元格,然后使用自动布局在单元格中布局元素。如果内容的高度增加,单元格的高度也会增加。这非常有用,我想知道是否可以在 table 视图中对 headers 部分完成相同的壮举?

例如,可以在 tableView:viewForHeaderInSection: 中创建一个 UIView,添加一个 UILabel 子视图,针对视图指定标签的自动布局约束,并增加视图高度以适合标签的内容,而无需实施 tableView:heightForHeaderInSection:?

viewForHeaderInSection 的文档指出:"This method only works correctly when tableView:heightForHeaderInSection: is also implemented." 我还没有听说 iOS 8.

是否有任何变化

如果不能做到这一点,模仿这种行为的最佳方式是什么?

这是可能的。它与 iOS 8.

中引入的动态单元格高度一起是新的

为此,请为部分 header 高度使用自动尺寸标注,如果需要,您可以提供估计的部分 header 高度。这可以在选择 table 视图时在 Interface Builder 中完成,也可以通过编程方式完成:

tableView.sectionHeaderHeight = UITableView.automaticDimension
tableView.estimatedSectionHeaderHeight = 38

//You can use tableView(_:heightForHeaderInSection:) and tableView(_:estimatedHeightForHeaderInSection:)
//if you need to support different types of headers per section

然后实施 tableView(_:viewForHeaderInSection:) 并根据需要使用自动布局来限制视图。一定要完全约束到UITableViewHeaderFooterViewcontentView,尤其是top-to-bottom,这样高度就可以由约束决定了。就是这样!

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {    
    let headerView = UITableViewHeaderFooterView()
    headerView.translatesAutoresizingMaskIntoConstraints = false
    headerView.backgroundView = {
        let view = UIView()
        view.backgroundColor = myCustomColor
        return view
    }()

    let headerLabel = UILabel()
    headerLabel.translatesAutoresizingMaskIntoConstraints = false
    headerLabel.text = "Hello World"
    headerView.contentView.addSubview(headerLabel)
    
    NSLayoutConstraint.activate([
        headerLabel.leadingAnchor.constraint(equalTo: headerView.contentView.leadingAnchor, constant: 16),
        headerLabel.trailingAnchor.constraint(equalTo: headerView.contentView.trailingAnchor, constant: -16),
        headerLabel.topAnchor.constraint(equalTo: headerView.contentView.topAnchor, constant: 12),
        headerLabel.bottomAnchor.constraint(equalTo: headerView.contentView.bottomAnchor, constant: -12)
    ])
    
    return headerView
}

这可以通过在 table 视图上设置(或返回)estimatedSectionHeaderHeight 来完成。

如果您的部分 header 在设置 estimatedSectionHeaderHeight 后与您的单元格重叠,请确保您也使用了 estimatedRowHeight .

(我添加这个答案是因为第二段包含一个问题的答案,可以在阅读所有可能会错过的评论后找到。)

我试过了

self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
self.tableView.estimatedSectionHeaderHeight = 25;

但它的大小不正确 header 带有多行标签。 添加这个来解决我的问题:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // Recalculates height
    tableView.beginUpdates()
    tableView.endUpdates()
}

我修改了iuriimoz 。刚刚替换了 viewWillAppear 方法:

tableView.sectionHeaderHeight = UITableViewAutomaticDimension
tableView.estimatedSectionHeaderHeight = 25


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // Recalculates height
    tableView.layoutIfNeeded() 
}

同时将 tableView.layoutIfNeeded() 添加到

override func viewDidAppear(_ animated: Bool) {

    super.viewDidAppear(animated)
    tableView.layoutIfNeeded()
}

对于iOS 10

tableView.beginUpdates()
tableView.endUpdates()

我的 viewWillAppear 有 "fade" 动画效果

是的,它适合我。我必须做出如下更多更改:

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let label = UILabel()

    label.numberOfLines = 0
    label.text          = my own text

    return label
}

就我而言:

  1. 以编程方式设置无效

self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension.

  1. 在情节提要中设置无效

  2. 覆盖 heightForHeaderInSection 有效

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

测试环境:

  • Mac OS 10.13.4
  • XCode 版本 9.4.1
  • 模拟器iPhone8 Plus

陷入相同的问题,其中 header 的高度一直为零,除非我在委托中为 heighForHeaderInSection.

提供固定高度

尝试了很多解决方案,其中包括

self.tableView.sectionHeaderHeight = UITableView.automaticDimension
self.tableView.estimatedSectionHeaderHeight = 73

但没有任何效果。我的手机也使用了适当的自动布局。使用以下代码动态更改行的高度,但 header 部分没有。

self.tableView.estimatedRowHeight = 135
self.tableView.rowHeight = UITableView.automaticDimension

修复非常简单也很奇怪,但我必须实现委托方法而不是 estimatedSectionHeaderHeightsectionHeaderHeight 的 1 行代码,我的情况如下所示。

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return UITableView.automaticDimension
}

func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
    return 73
}

Swift 4+

工作(测试 100%)

如果您需要这两个部分以及具有基于内容的动态高度的行,那么您可以使用以下代码:

在 viewDidLoad() 上写下这行:

    self.globalTableView.estimatedRowHeight = 20
    self.globalTableView.rowHeight = UITableView.automaticDimension

    self.globalTableView.sectionHeaderHeight =  UITableView.automaticDimension
    self.globalTableView.estimatedSectionHeaderHeight = 25;

现在我们已经使用 UITableView Delegate 方法设置了行高和节高:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
   {
       return UITableView.automaticDimension
   }
   func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

       return UITableView.automaticDimension

   }

Swift5,iOS12+

对我有用的唯一方法是

tableView.sectionHeaderHeight = UITableView.automaticDimension
tableView.estimatedSectionHeaderHeight = 40
tableView.estimatedRowHeight = 80

然后为自定义 header 视图元素设置约束,以便自动布局引擎可以确定它们的 x、y 位置和行高。即

NSLayoutConstraint.activate([
    titleLabel.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
    titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor),
    titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -24)
])