Reputation: 1179
I'm using uitableview in container view, so want to set my container height based on content size height. So after reloading tableview i'm changing height of container.but it seems it is calculating based on estimated height. it's not giving actual height.
This is my constraints layout.
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()
}
Now I'm reloading from my container view controller and chnanging height
Upvotes: 8
Views: 11174
Reputation: 4356
While the answer provided here is correct, here's another explanation from Apple Developer Forum, which states the contentSize is just as estimated
value initially. So making that to zero worked for me.
tableView.estimatedRowHeight = 0
Here's the answer from apple developer forum:
In iOS 11, table views use estimated heights by default. This means that the contentSize is just as estimated value initially. If you need to use the contentSize, you’ll want to disable estimated heights by setting the 3 estimated height properties to zero: tableView.estimatedRowHeight = 0 tableView.estimatedSectionHeaderHeight = 0 tableView.estimatedSectionFooterHeight = 0
Upvotes: 2
Reputation: 1025
If you're using iOS 13 and or Combine (like I am) then you can use the publisher from the tableview's KVO properties
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)
This works really nicely for me and publishes new values each layout pass which you can see real time on a device if you drop a breakpoint in the sink
closure.
Upvotes: 1
Reputation: 1179
I tried reloadData()
and layoutIfNeeded()
and tried many different ways. nothing has worked for me. Finally I solved it by using KVO
.
Here is my code
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
}
}
}
Upvotes: 41
Reputation: 9503
Most of your approach is right, add this below steps too. If you already done any step put as check mark.
numberOfLines
property to zeroImplement 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
}
Now run your project and check.
Expected output:
Upvotes: 2