【问题标题】:Set UITableView's height to the height of its content with Auto Layout使用 Auto Layout 将 UITableView 的高度设置为其内容的高度
【发布时间】:2016-01-20 23:46:09
【问题描述】:

我有一个视图,里面有两个标签和一个表格视图。我希望标签 1 始终位于我的表格视图上方,而标签 2 位于表格视图下方。问题是表格视图需要自动调整大小,这意味着增加或减少高度。

现在我有一个约束说 Table View 的高度总是等于 85 和一个 @IBOutlet 到我可以更改常量的高度约束。

我猜我需要将常数更改为所有单元格的高度,但我不确定如何。

【问题讨论】:

  • 另一种解决方案是创建UITableView 的子类,将其自己的intrinsicContentSize.height 设置为其contentSize.height。见stackoverflow.com/a/17335818/77567
  • @robmayoff 答案在我看来更好,因为它比 joern 答案更有活力。
  • 我知道这不是您问题的答案,但您是否考虑过使用 UIStackview 而不是 tableview?

标签: ios swift xcode uitableview nslayoutconstraint


【解决方案1】:

您必须在 UIViewController 中覆盖 updateViewConstraints() 并将高度约束的常量设置为 tableView.contentSize.height:

override func updateViewConstraints() {
    tableHeightConstraint.constant = tableView.contentSize.height
    super.updateViewConstraints()
}

然后你必须确保Label2 有一个顶部约束,即greaterThanOrEqual 到表视图的底部。而且您还必须将表格视图的高度约束的优先级从Required 更改为High,以避免在表格视图的contentHeight 大于可用高度时发生冲突。

【讨论】:

  • 在 viewDidLayoutSubviews 中添加这个,对我有用。
  • @GMHSJ,afaik viewDidLayoutSubviews 是在布局系统计算完帧后调用的,因此如果你在这里更改约束,它会再次触发布局过程,最终会产生无限递归。
  • @vahotm:没错,但是 updateViewConstraints 对我不起作用。不知道为什么:(
  • 虽然我认为这是一个很好的解决方案,但它需要您根据约束调整 tableview 的高度。我发现 nova 下面的解决方案更好,因为它不依赖于使用约束来改变高度。在我的例子中,我的 tableView 是一个 subview,superview 需要根据 tableView 的大小调整自己的框架。
  • @GMHSJ,在updateViewConstraints 末尾调用super.updateViewConstraints() 方法有帮助吗?因为这是根据the documentation覆盖它的正确方法。
【解决方案2】:

还有另一种方法可以做到这一点。 您可以在 table view contentSize 变量上添加观察者,并在 table view 内容更改时添加自己的大小。

@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var tableHeightConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    tableView.layer.removeAllAnimations()
    tableHeightConstraint.constant = tableView.contentSize.height
    UIView.animate(withDuration: 0.5) {
        self.updateViewConstraints()
    }

}

【讨论】:

  • 它对我有用。但是“observeValueForKeyPath”方法被多次调用。
  • @iKT 当您使用 NSKeyValueObservingOptions.new 观察键时,每次该键更新为新值时都会调用您,因此您可以随时删除该观察者
  • 这救了我的命
  • 太棒了,拯救我的一天
  • 有用。这不是一种优雅的方式。实际上很多年,APPLE 并没有通过事件 didFinishLoad 实现一种时尚的方式来做到这一点,如“tableview.contentSize”。但到目前为止,这是一种更简洁的方法,无需创建特定的类或扩展来处理此类普通任务。
【解决方案3】:

下面的代码对我有用。

  1. 为 tableViewHeight 创建一个插座。
@IBOutlet weak var tableViewHeight: NSLayoutConstraint!
var tableViewHeight: CGFloat = 0  // Dynamically calcualted height of TableView.
  1. 对于单元格的动态高度,我使用了以下代码:
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return tableView.estimatedRowHeight
}
  1. 对于 TableView 的高度,以及 TableView 单元格的动态高度:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    print(cell.frame.size.height, self.tableViewHeight)
    self.tableViewHeight += cell.frame.size.height
    tableViewBillsHeight.constant = self.tableViewHeight
}

说明:

TableView 单元格创建后,我们获取即将显示的单元格的框架高度,并将该单元格的高度添加到主 TableView 中。

【讨论】:

    【解决方案4】:

    在 Swift 4.2 和 Xcode 10.1 中

    这里有两个选项可以根据内容动态设置 UITableView 的高度。

    1) 如果您获得内容大小,请在viewDidLayoutSubviews() 中使用此代码

    DispatchQueue.main.async {
      var frame = self.TblView.frame
      frame.size.height = self.TblView.contentSize.height
       self.TblView.frame = frame
    }
    

    2) 基于表视图高度约束更新表视图高度。在重新加载表视图时得到服务器的响应后编写此代码。

    DispatchQueue.main.async {
        self.TblViewHeightConstraint.constant = CGFloat((self.array.count) * 30)//Here 30 is my cell height
         self.TblView.reloadData()
    }
    

    【讨论】:

      【解决方案5】:

      将@nova 答案扩展到 swift 4

      tableViewSizeObservation = tableView.observe(\.contentSize) { [weak self] (tableView, _) in
         tableView.layer.removeAllAnimations()
         self?.tableViewHeightContraint.constant = tableView.contentSize.height
         UIView.animate(withDuration: 0.5) {
               self?.view.updateConstraints()
               self?.view.layoutIfNeeded()
         }
      }
      
      deinit {
          tableViewSizeObservation?.invalidate()
      }
      

      【讨论】:

        【解决方案6】:

        对于 TableView 高度自动调整及其内容大小,请在 ViewController 类中使用它。

        //constraintTableViewHeight :- tableview height constraint 
        
        override func viewWillLayoutSubviews() {
            super.updateViewConstraints()
            self.constraintTableViewHeight.constant = self.tableView.contentSize.height
        }
        

        并添加这个

        func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            self.viewWillLayoutSubviews()
        }
        

        这段代码很容易根据内容大小自动调整tableview的高度。

        【讨论】:

          【解决方案7】:

          一种更现代的方式是这样做:

          override func updateViewConstraints() {
              tableView.heightAnchor.constraint(equalToConstant: tableView.contentSize.height).isActive = true
              super.updateViewConstraints()
          }
          

          【讨论】:

          • 但是每次调用updateViewConstraints 时,都会创建一个新的约束。因此,您正在累积多个高度约束,因此如果 tableView.contentSize 发生变化,您将获得具有冲突值的高度约束。因此,存储高度约束并始终更新该约束是值得的(您可以在 viewDidLoad 中创建它)。此外,即使尺寸永远不会改变,自动布局也必须做更多的工作来处理额外的约束。
          【解决方案8】:
          override func viewDidLayoutSubviews() {
                super.viewDidLayoutSubviews()      
                     let contentheight = tableView.contentSize.height
                     self.tableHeightConstraint.constant = contentheight
            }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-19
            • 2011-12-09
            • 2021-08-28
            • 2016-11-08
            • 1970-01-01
            相关资源
            最近更新 更多