UITableView的内容大小未正确返回(Swift)

8
我正在使用容器视图中的uitableview,所以想要根据内容大小高度设置我的容器高度。因此,在重新加载tableview后,我更改了容器的高度,但似乎它是基于估计高度计算的,而不是实际高度。
这是我的约束布局。
谢谢..enter image description here
    instructiontableview.estimatedRowHeight = 55

    instructiontableview.rowHeight = UITableViewAutomaticDimension

 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension

  }

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    // assigning multiline text to my label 


        cell.layoutIfNeeded()
        cell.sizeToFit()
        return cell
    }
    return UITableViewCell()
}

现在我正在从我的容器视图控制器中重新加载,并更改高度。

1
请添加相关的代码和限制条件。 - dahiya_boy
@agent_stack请检查我的更新问题。 - siva krishna
你的标签内容正在改变,根据该内容,你需要更改单元格的高度。我是正确的吗? - dahiya_boy
4个回答

40

我尝试了 reloadData()layoutIfNeeded() 以及许多不同的方法,但都没有起作用。最后我通过使用 KVO 解决了这个问题。

以下是我的代码:

override  func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.instructiontableview.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)

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

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?){
    if(keyPath == "contentSize"){

        if let newvalue = change?[.newKey]{
            let newsize  = newvalue as! CGSize
            self.heightofinstructioncontainerview.constant = newsize.height
        }
    }
} 

3
感谢上帝免税。 - Wez
在我尝试过的所有方法之后,这是唯一有效的解决方案。在iOS 13中存在一个bug,即"tableView.contentSize.height" 返回的值不正确。如答案所示观察该属性可提供其真实值。 - Starwave
不可能!这是我在iOS 13中找到的唯一解决方案!非常感谢! - PhillipJacobs
经过一整天的搜索,我现在可以放心睡觉了。这个解决方案非常完美。 - Mohammed Hasan
非常好的答案适用于(iOS 13,*)。谢谢。 - Muhammad Danish Qureshi
救了我的一天!我想说又是一天:D - Raja Saad

2
您的大部分方法是正确的,请添加以下步骤。如果您已经完成了任何步骤,请打上勾。
  1. 将标签numberOfLines属性更改为零

enter image description here

  1. 添加标签约束

enter image description here

  1. 更改高度约束关系

enter image description here

  1. Implement these two tableView delegates methods

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat{
          return 55
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
          return UITableViewAutomaticDimension
    }
    
现在运行你的项目并检查。
预期输出: enter image description here

我没有添加uilabel高度,除此之外我完成了所有步骤。 - siva krishna

2

虽然这里提供的答案是正确的,但以下是来自苹果开发者论坛Apple Developer Forum的另一个解释,它指出contentSize最初只是一个估计值。因此,将其设置为零对我很有效。

tableView.estimatedRowHeight = 0

以下是来自苹果开发者论坛的答案:

iOS 11中,表格视图默认使用估计高度。这意味着contentSize最初只是一个估计值。如果您需要使用contentSize,您需要通过将三个估计高度属性设置为零来禁用估计高度:tableView.estimatedRowHeight = 0 tableView.estimatedSectionHeaderHeight = 0 tableView.estimatedSectionFooterHeight = 0


1
如果您正在使用iOS 13或Combine(就像我一样),那么您可以使用来自tableview的KVO属性的发布者。
tableView.publisher(for: \.contentSize)
       .receive(on: RunLoop.main)
       .sink { size in
           self.myViewsHeightConstraint.constant = size.height
           self.tableView.isScrollEnabled = size.height > self.tableView.frame.height
       }
       .store(in: &cancellables)

这对我非常有帮助,每次布局通过后都会发布新的值,如果您在“sink”闭包中设置断点,可以实时在设备上查看。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接