【问题标题】:Is it possible to obtain a dynamic table view section header height using Auto Layout?是否可以使用自动布局获得动态表格视图部分标题高度?
【发布时间】:2015-06-10 07:44:56
【问题描述】:

iOS 8 中的新功能,您可以通过简单地设置估计的行高来获得 100% 动态表格视图单元格,然后使用自动布局在单元格中布局您的元素。如果内容的高度增加,单元格的高度也会增加。这非常有用,我想知道是否可以为表格视图中的节标题完成相同的壮举?

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

viewForHeaderInSection 的文档指出:“此方法仅在 tableView:heightForHeaderInSection: 也实现时才能正常工作。”我还没有听说 iOS 8 是否有任何变化。

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

【问题讨论】:

    标签: ios uitableview ios8 autolayout


    【解决方案1】:

    这是可能的。它是 iOS 8 中引入的动态单元格高度旁边的新功能。

    为此,请为节标题高度使用自动尺寸,如果需要,您可以提供估计的节标题高度。这可以在选择表视图或以编程方式在 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,尤其是从上到下,这样高度可以由约束来确定。就是这样!

    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
    }
    

    【讨论】:

    • 如果它有效,那就太酷了,但是文档没有提到它,如果我没记错的话,WWDC 会议也没有提到。 UITableViewAutomaticDimension 的文档说“如果您在 tableView:heightForHeaderInSection:tableView:heightForFooterInSection: 中返回此常量,UITableView 使用适合从 tableView:titleForHeaderInSection:tableView:titleForFooterInSection: 返回的值的高度(如果标题不是 nil )。”
    • 这对我不起作用。我的部分标题能够自动计算高度,但它与部分中的单元格重叠。我正在使用 xib 文件设置我的标题视图并在界面生成器中设置我的约束。那是我的问题吗?你们在哪里创建约束?谢谢!
    • 这里承诺的是示例代码:github.com/ebetabox/DynamicCellSectionHeight
    • 这里的另一个关键点,您的表格单元格还需要配置为自动高度 (UITableViewAutomaticDimension) 计算,以便它在部分上工作。
    • 您必须拥有estimatedSectionHeaderHeighttableView:estimatedHeightForHeaderInSection:sectionHeaderHeighttableView:heightForHeaderInSection:。此外,如果您使用委托方法,您必须返回一个大于 1.00 的估计值(完全未记录的行为),否则高度的委托将不会被调用,并且将使用默认的表格视图标题高度。跨度>
    【解决方案2】:

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

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

    (我之所以添加这个答案,是因为第二段包含了一个问题的答案,该问题可以在通读所有可能遗漏的 cmets 后找到。)

    【讨论】:

    • 谢谢,在设置 estimatedRowHeight 之后,这就像魅力 :)
    • 即使您没有对行使用 UITableViewAutomaticDimension 也是如此。感谢您为我节省了一个小时。
    【解决方案3】:

    我试过了

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

    但它没有正确调整带有多行标签的标题。 添加这个来解决我的问题:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    
        // Recalculates height
        tableView.beginUpdates()
        tableView.endUpdates()
    }
    

    【讨论】:

    • 请定义数据源函数tableView:estimatedHeightForHeaderInSectiontableView:heightForHeaderInSection,而不是在viewDidLoad 中定义。
    • 我发现设置estimatedSectionHeaderHeight只有在iOS 11以下才需要
    • 这是一个很好的解决方案。如果有人遇到“高度不明确”错误,请使用 tableView.reloadData() 而不是 .beginUpdates() 和 endUpdates() 修复它。
    • 仍然不适合我。我在标题视图中有一个标签和文本字段。
    【解决方案4】:

    我修改了iuriimozanswer。刚刚替换了 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 有“淡出”动画效果

    【讨论】:

      【解决方案5】:

      是的,它对我有用。我必须进行更多更改,如下所示:

      override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
          let label = UILabel()
      
          label.numberOfLines = 0
          label.text          = my own text
      
          return label
      }
      

      【讨论】:

        【解决方案6】:

        就我而言:

        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
        • 模拟器 iPhone 8 Plus

        【讨论】:

          【解决方案7】:

          陷入了同样的问题,即标题高度为零,除非我在代理中为 heighForHeaderInSection 提供固定高度。

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

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

          但没有任何效果。我的单元格也使用了正确的自动布局。通过使用以下代码,行正在动态更改其高度,但节标题没有。

          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
          }
          

          【讨论】:

            【解决方案8】:

            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
            
               }
            

            【讨论】:

            • 注意这个很好的答案。 截至 2020 年似乎可以只使用 viewDidLoad 中的四个属性。
            • 注意这个很好的答案。 截至 2020 年,您确实需要两条“无用”线来给出估计高度(例如,20 左右)。
            【解决方案9】:

            Swift 5、iOS 12+

            它对我有用的唯一方法是

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

            然后为自定义标题视图元素设置约束,以便自动布局引擎可以确定它们的 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)
            ])
            

            【讨论】:

              猜你喜欢
              • 2013-05-16
              • 2018-02-22
              • 2013-06-29
              • 1970-01-01
              • 2019-04-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多