Reputation: 1557
Text data of variable length are being injected into tableview cell labels. In order for each cell height to be properly sized, I have implemented in viewDidLoad()
:
self.tableView.estimatedRowHeight = 88.0
self.tableView.rowHeight = UITableViewAutomaticDimension
This estimates the height to be 88.0 pixels and should resize the height automatically if larger. It works perfectly for cells that have yet to be scrolled to (as UITableViewAutomaticDimention
is called upon scrolling to the cell), but not for the cells that are initially rendered onscreen upon loading the table with data.
I have tried reloading the data (as suggested in many other resources):
self.tableView.reloadData()
in both viewDidAppear()
and viewWillAppear()
and it did not help. I am lost.. does anyone know how to render the dynamic height for the cells loaded initially on screen?
Upvotes: 95
Views: 203674
Reputation: 29
Swift 5.0 working nice
override func viewWillAppear(_ animated: Bool){
super.viewWillAppear(true)
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableView.automaticDimension
tableView.reloadData()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat{
return UITableView.automaticDimension
}
Upvotes: -1
Reputation: 267
What worked for me was creating a height constraint on my custom cell that I set at runtime (I've got an expand/collapse button in each cell).
Then in heightForRowAt in the parent, I had to do a combination of suggested answers:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if let cell = tableView.cellForRow(at: indexPath) as? GroupTableViewCell {
return cell.heightConstraint.constant
}
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 88.0
}
I use the already calculated height constraint constant where it's available and UITableView.automaticDimension otherwise. This was the only way to get the correct height and maintain the correct cell state when the cell gets recycled.
I hear it's considered bad practice to reference the cell itself inside heightForRowAt, but I don't see another way of doing it with custom cell objects with dynamic heights whilst keeping all constraints satisfied.
Upvotes: 1
Reputation: 6013
Swift 5 Enjoy
tablev.rowHeight = 100
tablev.estimatedRowHeight = UITableView.automaticDimension
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tablev.dequeueReusableCell(withIdentifier: "ConferenceRoomsCell") as! ConferenceRoomsCell
cell.lblRoomName.numberOfLines = 0
cell.lblRoomName.lineBreakMode = .byWordWrapping
cell.lblRoomName.text = arrNameOfRooms[indexPath.row]
cell.lblRoomName.sizeToFit()
return cell
}
Upvotes: -3
Reputation: 1907
This is simple when doing 2 things:
tableView.rowHeight = UITableView.automaticDimension
So the layout engine can compute the cell heigth and apply the value correctly.
Upvotes: 4
Reputation: 933
Use this:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300
and don't use: heightForRowAtIndexPath
delegate function
Also, in the storyboard don't set the height of the label that contains a large amount of data. Give it top, bottom, leading, trailing
constraints.
Upvotes: 48
Reputation: 25
self.Itemtableview.estimatedRowHeight = 0;
self.Itemtableview.estimatedSectionHeaderHeight = 0;
self.Itemtableview.estimatedSectionFooterHeight = 0;
[ self.Itemtableview reloadData];
self.Itemtableview.frame = CGRectMake( self.Itemtableview.frame.origin.x, self.Itemtableview.frame.origin.y, self.Itemtableview.frame.size.width,self.Itemtableview.contentSize.height + self.Itemtableview.contentInset.bottom + self.Itemtableview.contentInset.top);
Upvotes: -1
Reputation: 7943
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0
And don't forget to add botton constraints for label
Upvotes: 2
Reputation: 562
When using a static UITableView
, I set all the values in the UILabel
s and then call tableView.reloadData()
.
Upvotes: 1
Reputation: 404
In addition to what others have said,
SET YOUR LABEL'S CONSTRAINTS RELATIVE TO THE SUPERVIEW!
So instead of placing your label's constraints relative to other things around it, constrain it to the table view cell's content view.
Then, make sure your label's height is set to more than or equal 0, and the number of lines is set to 0.
Then in ViewDidLoad
add:
tableView.estimatedRowHeight = 695
tableView.rowHeight = UITableViewAutomaticDimension
Upvotes: 5
Reputation: 578
In my case - In storyboard i had a two labels as in image below, both labels was having desired width values been set before i made it equal. once you unselect, it will change to automatic, and as usual having below things should work like charm.
1.rowHeight = UITableView.automaticDimension, and
2.estimatedRowHeight = 100(In my case).
3.make sure label number of lines is zero.
Upvotes: 5
Reputation: 143
I use these
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
Upvotes: 3
Reputation: 475
Unfortunately, I am not sure what I was missing. The above methods don't work for me to get the xib cell's height or let the layoutifneeded()or UITableView.automaticDimension to do the height calculation. I've been searching and trying for 3 to 4 nights but could not find an answer. Some answers here or on another post did give me hints for the workaround though. It's a stupid method but it works. Just add all your cells into an Array. And then set the outlet of each of your height constraint in the xib storyboard. Finally, add them up in the heightForRowAt method. It's just straight forward if you are not familiar with the those APIs.
Swift 4.2
CustomCell.Swift
@IBOutlet weak var textViewOneHeight: NSLayoutConstraint!
@IBOutlet weak var textViewTwoHeight: NSLayoutConstraint!
@IBOutlet weak var textViewThreeHeight: NSLayoutConstraint!
@IBOutlet weak var textViewFourHeight: NSLayoutConstraint!
@IBOutlet weak var textViewFiveHeight: NSLayoutConstraint!
MyTableViewVC.Swift
.
.
var myCustomCells:[CustomCell] = []
.
.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("CustomCell", owner: self, options: nil)?.first as! CustomCell
.
.
myCustomCells.append(cell)
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let totalHeight = myCustomCells[indexPath.row].textViewOneHeight.constant + myCustomCells[indexPath.row].textViewTwoHeight.constant + myCustomCells[indexPath.row].textViewThreeHeight.constant + myCustomCells[indexPath.row].textViewFourHeight.constant + myCustomCells[indexPath.row].textViewFiveHeight.constant
return totalHeight + 40 //some magic number
}
Upvotes: 3
Reputation: 1308
For Swift 4.2
@IBOutlet weak var tableVw: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Set self as tableView delegate
tableVw.delegate = self
tableVw.rowHeight = UITableView.automaticDimension
tableVw.estimatedRowHeight = UITableView.automaticDimension
}
// UITableViewDelegate Method
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Happy Coding :)
Upvotes: 4
Reputation: 3205
Try This:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
EDIT
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Swift 4
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Swift 4.2
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Define above Both Methods.
It solves the problem.
PS: Top and bottom constraints is required for this to work.
Upvotes: 135
Reputation: 17882
For Swift i checked this answer in iOS 9.0 and iOS 11 also (Xcode 9.3)
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Here you need to add top, bottom, right and left constraints
Upvotes: 4
Reputation: 79636
Set automatic dimension for row height & estimated row height and ensure following steps:
@IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Set automatic dimensions for row height
// Swift 4.2 onwards
table.rowHeight = UITableView.automaticDimension
table.estimatedRowHeight = UITableView.automaticDimension
// Swift 4.1 and below
table.rowHeight = UITableViewAutomaticDimension
table.estimatedRowHeight = UITableViewAutomaticDimension
}
// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// Swift 4.2 onwards
return UITableView.automaticDimension
// Swift 4.1 and below
return UITableViewAutomaticDimension
}
For Example: if you have a label in your UITableviewCell then,
Here is sample label with dynamic height constraints.
Upvotes: 13
Reputation: 1376
I had also got this issue initially, I had resolved my issue from this code
try avoiding the use of self.tableView.reloadData()
instead of this code for dynamic height
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
Upvotes: 1
Reputation: 17882
For objective c this is one of my nice solution. it's worked for me.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cell.textLabel.text = [_nameArray objectAtIndex:indexPath.row];
cell.textLabel.numberOfLines = 0;
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
We need to apply these 2 changes.
1)cell.textLabel.numberOfLines = 0;
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
2)return UITableViewAutomaticDimension;
Upvotes: 2
Reputation: 41
To make autoresizing of UITableViewCell to work make sure you are doing these changes :
In your UIViewController's viewDidLoad function set below UITableView Properties :
self.tableView.estimatedRowHeight = <minimum cell height>
self.tableView.rowHeight = UITableViewAutomaticDimension
Upvotes: 4
Reputation: 31
You should just set all constraints for TOP, BOTTOM and HEIGHT for each object on cell view/views and remove exists middle Y position if have. Because where you didn't this, puts artifacts on another views.
Upvotes: 3
Reputation: 1557
This strange bug was solved through Interface Builder parameters as the other answers did not resolve the issue.
All I did was make the default label size larger than the content potentially could be and have it reflected in the estimatedRowHeight
height too. Previously, I set the default row height in Interface Builder to 88px
and reflected it like so in my controller viewDidLoad()
:
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0
But that didn't work. So I realized that content wouldn't ever become larger than maybe 100px
, so I set the default cell height to 108px
(larger than the potential content) and reflected it like so in the controller viewDidLoad()
:
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 108.0
This actually allowed the code to shrink down the initial labels to the correct size. In other words, it never expanded out to a larger size, but could always shrink down... Also, no additional self.tableView.reloadData()
was needed in viewWillAppear()
.
I know this does not cover highly variable content sizes, but this worked in my situation where the content had a maximum possible character count.
Not sure if this is a bug in Swift or Interface Builder but it works like a charm. Give it a try!
Upvotes: 16
Reputation: 1296
Dynamic sizing cell of UITableView required 2 things
Calling these properties of TableView in viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 140
This is a wonderfull tutorial on self-sizing (dynamic table view cells) written in swift 3 .
Upvotes: 8
Reputation: 662
Set proper constraint and update delegate methods as:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
This will resolve dynamic cell height issue. IF not you need to check constraints.
Upvotes: -2
Reputation: 3906
For Swift 3 you can use the following:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Upvotes: 9
Reputation: 3225
SWIFT 3
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 160
AND!!! In storyBoard: You HAVE TO set TOP & BOTTOM constraints for your Label. Nothing else.
Upvotes: 19
Reputation: 21
Try
override func viewWillAppear(animated: Bool) {
self.tableView.layoutSubviews()
}
I had the same problem and it works for me.
Upvotes: 2
Reputation: 21
I was just inspired by your solution and tried another way.
Please try to add tableView.reloadData()
to viewDidAppear()
.
This works for me.
I think the things behind scrolling is "the same" as reloadData. When you scroll the screen, it's like calling reloadData()
when viewDidAppear
.
If this works, plz reply this answer so I could be sure of this solution.
Upvotes: 1