【问题标题】:How to get height of UITableView when cells are dynamically sized?动态调整单元格大小时如何获取 UITableView 的高度?
【发布时间】:2017-02-26 01:24:15
【问题描述】:

我有一个 UITableView,其中包含动态大小的单元格。这意味着我已经设置:

tableView.estimatedRowHeight = 50.0
tableView.rowHeight = UITableViewAutomaticDimension

现在我想获取整个表格视图的高度。我尝试通过tableView.contentSize.height 获取它,但它只返回估计的行高,而不是表格视图的实际动态高度。

如何获取整个表格视图的动态高度?

【问题讨论】:

标签: ios swift uitableview


【解决方案1】:

我终于想出了一个解决方案:

tableView.contentSize.height 不适用于动态单元格,因为它们只会返回单元格数 * estimatedRowHeight

因此,要获得动态表格视图高度,您需要查找所有可见单元格,并将它们的高度相加。请注意,这只适用于比屏幕短的表格视图。

但是,在我们执行上述查找可见单元格之前,重要的是要知道注意我们需要在屏幕上获取表格视图,以便我们可以获得可见单元格。为此,我们可以将 table view 的高度约束设置为任意大的数字,以便它出现在屏幕上:

  1. 设置表格视图约束的高度:

    // Class variable heightOfTableViewConstraint set to 1000
    heightOfTableViewConstraint = NSLayoutConstraint(item: self.tableView, attribute: .height, relatedBy: .equal, toItem: containerView, attribute: .height, multiplier: 0.0, constant: 1000)
    containerView.addConstraint(heightOfTableViewConstraint)
    
  2. 调用tableView.layoutIfNeeded(),完成后寻找可见单元格,求和它们的高度,编辑heightOfTableViewConstraint

    UIView.animate(withDuration: 0, animations: {
        self.tableView.layoutIfNeeded()
        }) { (complete) in
            var heightOfTableView: CGFloat = 0.0
            // Get visible cells and sum up their heights
            let cells = self.tableView.visibleCells
            for cell in cells {
                heightOfTableView += cell.frame.height
            }
            // Edit heightOfTableViewConstraint's constant to update height of table view
            self.heightOfTableViewConstraint.constant = heightOfTableView
    }
    

【讨论】:

  • 你在哪里调用这段代码来更新tableView的高度约束?
  • 这对我有用,但我必须把我的代码放在viewDidLayoutSubviews() 因为viewDidLoad() 中的单元格还没有加载。
  • 这是一个非常有价值的答案!我需要为使用自调整单元格的今日扩展小部件更改表格视图的高度(我以编程方式执行此操作)。诀窍是(如您所说)将高度设置为 1000 以扩展所有单元格,然后将单元格可见高度相加,然后使用 layoutIf 需要设置新高度。太好了,谢谢。
  • 如果我有多个部分并且需要获取 tableview 的总高度怎么办?
  • 这种东西太老套了,让我很焦虑。苹果在做什么???
【解决方案2】:

上述解决方案非常好。我尝试了一种不同的方法,它的流畅和清晰易懂

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    tableView.removeObserver(self, forKeyPath: "contentSize")
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "contentSize"{
            if object is UITableView{
                if let newValue = change?[.newKey]{
                    let newSize = newValue as! CGSize
                    heightOfTableViewConstraint.constant = newSize.height
                }
            }
        }
    }

【讨论】:

  • 通常最后一个答案永远不是我的首选答案,但这个答案为我节省了 2 天的工作时间。在应用程序上线之前,我几乎要重做整个屏幕。谢谢老哥
【解决方案3】:

已经回答了,但我也想分享一下我的经验。

我也有同样的问题。我搜索了许多类似问题的答案,并尝试了他们的答案,但没有用。

我终于找到了leonardloo answer。非常感谢,但它还没有解决我的问题。我只是想完成他的回答。我把这段代码取自他的回答:

UIView.animate(withDuration: 0, animations: {
self.tableView.layoutIfNeeded()
}) { (complete) in
    var heightOfTableView: CGFloat = 0.0
    // Get visible cells and sum up their heights
    let cells = self.tableView.visibleCells
    for cell in cells {
        heightOfTableView += cell.frame.height
    }
    // Edit heightOfTableViewConstraint's constant to update height of table view
    self.heightOfTableViewConstraint.constant = heightOfTableView
}

在这段代码中:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    ...
    if indexPath.row == data.count-1{ 
        // Insert the code here
    }
    return cell
}

这意味着在表中的所有行都已加载后,我们使用那段代码更新行的高度。 有效!!!

【讨论】:

  • 这个有效!谢谢埃贝德!只是一个小问题。您需要在循环后再执行一次“heightOfTableView += cell.frame.height”,因为最后一个单元格还没有在可见单元中;)
  • 这里的答案部分有效,通过这样做我们只能得到可见单元格的高度,而不是所有的单元格
【解决方案4】:

尽管@leonardloo 的回答部分正确并且可能适合许多人的需求,但我还是想分享一下我是如何解决我的问题的。

我有一个很大的 tableView 有很大的行并且有同样的问题。当我应用@leonardloo 的答案时,我发现它只绘制了它在开始时发现的可见单元格的数量,它绘制了 1 行,而它应该绘制 5(我的数据源计数) .

为了解决这个问题,我找到了这样一个简单的解决方案:

UIView.animate(withDuration: 0, animations: {
self.tableView.layoutIfNeeded()
}) { (complete) in
    var heightOfTableView: CGFloat = 0.0
    // Get visible cells and sum up their heights
    let cells = self.tableView.visibleCells
    for cell in cells {
        heightOfTableView += cell.frame.height
    }
    // Edit heightOfTableViewConstraint's constant to update height of table view
    // Set tableView's constraint to height + 1 so that 
    // it can still draw the next visible cell it's supposed to.
    self.heightOfTableViewConstraint.constant = heightOfTableView + 1
}

这里的重点是让它绘制下一个单元格,以便通过将约束常量设置为 height + 1 来将其计算在 visibleCells 中。我已经测试过,现在它看起来像一个魅力。

【讨论】:

    【解决方案5】:

    你应该在下面的委托方法中计算tableView的高度,

    func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    
        //Get the height required for the TableView to show all cells
        if indexPath.row() == (tableView.indexPathsForVisibleRows.last! as! NSIndexPath).row {
            //End of loading all Visible cells
            float heightRequiredForTable = tableView.contentSize.height
    
            //If cell's are more than 10 or so that it could not fit on the tableView's visible area then you have to go for other way to check for last cell loaded 
        }
    }
    

    【讨论】:

    • 我正在尝试获取表格视图的高度,以便以编程方式设置表格视图的约束。我不认为上述工作..
    • 如果要将 tableView 的高度设置为所有单元格所需的高度,则需要将 UITableView 添加为 UIScrollView 的子项,然后创建 heightConstraint 并在相同的委托方法中更新它正如我对这个问题的回答中所解释的那样 - stackoverflow.com/questions/38044803/…
    【解决方案6】:

    只需维护一个CGFLoat 类型的数组并将UITableViewAutomaticDimension 附加到cellForRowAt indexPathtableview 代表中

    var cellHeight = [CGFloat]()
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    cellHeight.append(UITableViewAutomaticDimension)
    }
    

    【讨论】:

    • 抱歉(Bugs)后来编辑的语法错误,但它对我来说很好
    • 但在 swift 4.2 UITableView.automatic 中返回-1。有什么解决办法吗?
    【解决方案7】:

    我会在这里添加我的答案,因为我对此有点挣扎。

    我的表格视图使用带有标题的部分,因此仅获取可见单元格的高度是行不通的。我最终做的是首先为tableView 设置一个超大高度,以便将内容全部添加。然后在tableView 的最后一个cell 上,我将tableView 调整为与其content 相同的高度。

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      ... // do your normal cell processing
    
      // determine height and change it
      if indexPath.section == (self.sectionTitles.count - 1) && indexPath.row == (sectionData.count - 1) {
    
        UIView.animate(withDuration: 0, animations: {
          self.tableView.layoutIfNeeded()
        }) { complete in
    
          // Edit heightOfTableViewConstraint's constant to update height of table view
          self.tableViewHeightConstraint.constant = self.tableView.contentSize.height
        }
      }
    }
    

    【讨论】:

      【解决方案8】:

      你可以试试这个代码

      func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
          return UITableViewAutomaticDimension
      }
      
      func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
          return UITableViewAutomaticDimension
      }
      

      【讨论】:

      • 感谢您的建议。我试过了,但不幸的是它仍然不起作用。
      猜你喜欢
      • 2019-08-15
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多