why UITableViewAutomaticDimension not working?
Asked Answered
B

19

83

Hi there is plenty of question answering the dynamic height for UITableViewCell of UITableView. However I find it weird when I did it.

here's are some of the answer :

here and here

usually this would answer the dynamic height for cell

tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableView.automaticDimension

but in my case I wonder this line wont do anything.

my UITableView is being viewed after clicking tabbar inside the splitview. Is this helpful?

Maybe I'm Missing something. Could anyone help me I spent 2 hours doing silly.

These are my constraint for title the title could be long but the label is not.

enter image description here

and this is my cell

enter image description here

Bad answered 18/5, 2015 at 9:19 Comment(9)
You should double re-check with you UITableViewCell autolayout setup in xib/storyboard. You have some issue there 100%Requisition
yeah, Im rewriting it. Hope to find what causing itBad
If you post your xib/storyboard there, I can help you with itRequisition
Did you set your view constrains relative to top and bottom of your cell content view ?Korella
should i just do screenshot?Bad
Do you have constraint on a label with bottom space to superview ?Korella
@zellb I think i dont have, hmm..why? maybe im messing something with my constraintBad
@caffeineshots Just to be sure I didn't ask for a title label but for the label below it? If you don't have it, add and check the result. I think it still wont work but show me your results first then Im gonna tell you the next stepsKorella
Let us continue this discussion in chat.Bad
K
175

In order to make UITableViewAutomaticDimension work you have to set all left, right, bottom, and top constraints relative to cell container view. In your case you will need to add the missing bottom space to superview constraint for label under the title

Korella answered 18/5, 2015 at 10:32 Comment(3)
Note you will probably have to set the bottom constraints for some views to be >= rather than just = to allow them to grow with the dynamic height of the cell. This was the trick for me.Cauley
@Secular Are you sure that you are not using size classes?Korella
@ZellB. yea you are right. its due to a constraint was missing iPhone class. (Y)Secular
P
33

I had added constraints programmatically, and accidentally added them to the cell directly, i.e. not on the contentView property. Adding the constraints to contentView resolved it for me!

Photocathode answered 8/2, 2016 at 9:42 Comment(4)
yes we need to clearly know what constraint we use to what cos one constraint missing or added could cos ambiguity or not satisfied constraint.Thanks for answer man!Bad
I know this is old but i dont think this is the correct way to do this. If you dont add the constraints to the content view. The view will distort when you open any editing style for the cell like Deletion or moving the row it self.Kaylenekayley
@Kaylenekayley I think you are reading his answer wrong. He is stating that you need to add constraints to the contentView. I also accidentally added constraints to the UITableViewCell when it should be to the UITableViewCell's contentViewDobson
Thats what I said. If you don't add the constraints to the content view then the view will distort when you selecting an editing style like deletion or moving the row. Your not supposed to modify the cells view directly since UIKit modifies the cells layout when you hit editing mode and the cell shifts to the right.Your supposed to add all subviews and layout constraints to the content view. Not the View itselfKaylenekayley
T
28

To set automatic dimension for row height & estimated row height, ensure following steps to make, auto dimension effective for cell/row height layout.

  • Assign and implement tableview dataSource and delegate
  • Assign UITableViewAutomaticDimension to rowHeight & estimatedRowHeight
  • Implement delegate/dataSource methods (i.e. heightForRowAt and return a value UITableViewAutomaticDimension to it)

-

Objective C:

// in ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

  @property IBOutlet UITableView * table;

@end

// in ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    self.table.dataSource = self;
    self.table.delegate = self;

    self.table.rowHeight = UITableViewAutomaticDimension;
    self.table.estimatedRowHeight = UITableViewAutomaticDimension;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    return UITableViewAutomaticDimension;
}

Swift:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Don't forget to set dataSource and delegate for table
    table.dataSource = self
    table.delegate = self

    // 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 label instance in UITableviewCell

  • Set number of lines = 0 (& line break mode = truncate tail)
  • Set all constraints (top, bottom, right left) with respect to its superview/ cell container.
  • Optional: Set minimum height for label, if you want minimum vertical area covered by label, even if there is no data.

enter image description here

Note: If you've more than one labels (UIElements) with dynamic length, which should be adjusted according to its content size: Adjust 'Content Hugging and Compression Resistance Priority` for labels which you want to expand/compress with higher priority.

Televise answered 17/10, 2017 at 12:1 Comment(3)
implementing heightForRowAt with returning UITableView.automaticDimension workHyades
Don't return automaticDimension in the estimatedHeightForRowAt delegate method. It's there to hint to the table view the size of the cell.Ramify
setting the rowHeight and estimatedRowHeight in viewDidLoad solved the issue for me.Flagler
O
20

Also make sure the Lines for your UILabel in the cell is set to 0. If it is set to 1, it will not grow vertically.

Onehorse answered 3/10, 2015 at 13:46 Comment(0)
S
7

I have a specific case, and 99% of the solutions I read didn't work. I thought I'd share my experience. Hope it can helps, as I'd struggled for a couple of hours before fixing this issue.

My scenario:

  • I'm using two TableViews in one ViewController
  • I am loading Custom Cells (xib) in those tableviews
  • Dynamic content in cells consists of two labels
  • Page uses a ScrollView

What I needed to achieve:

  • Dynamic TableView height
  • Dynamic TableViewCells height

What you'll need to check to make it work smoothly:

  • Like every tutorial and answer will tell you, set all the constraints for your label/content (top, bottom, leading & trailing), and set it to the ContentView (Superview). This video tutorial will be helpful.

  • In the viewWillAppear method of my ViewController, I am giving one of my tableViews (tableView2) an estimated row height and then use the UITableViewAutomaticDimension as such (and as seen in all tutorials/answers):

        override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    
        tableView2.estimatedRowHeight = 80
        tableView2.rowHeight = UITableViewAutomaticDimension
    
    }
    

For me, these previous steps were not enough. My TableView would simply take the estimatedRowHeight and multiply it by the number of cells. Meeeh.

  • As I am using two different tableViews, I created an outlet for each of them, tableView1 and tableView2. Allowing me to resize them in the viewDidLayoutSubviews method. Feel free to ask in comment how I did this.

  • One additional step fixed it for me, by adding this to the viewDidAppear method:

    override func viewDidAppear(_ animated: Bool) {
    tableView1.reloadData() // reloading data for the first tableView serves another purpose, not exactly related to this question.
    tableView2.setNeedsLayout()
    tableView2.layoutIfNeeded()
    tableView2.reloadData()
    }
    

Hope that helps someone!

Saval answered 7/5, 2017 at 9:14 Comment(1)
the last advice (but without double IBOutlet) is still useful in 2019.Thermopylae
A
7

As of iOS 11 and Xcode 9.3, most of the above information is wrong. Apple's Guide suggests setting

    tableView.estimatedRowHeight = 85.0
    tableView.rowHeight = UITableViewAutomaticDimension

WWDC 2017 session 245 (Building Apps with Dynamic Type, about 16:33 into the video) suggests something similar. None of this made a difference for me.

For a Subtitle style cell, all that's necessary to get self-sizing table view cells is to set the number of lines (in the Label section of the attributes inspector) to 0 for both the Title and Subtitle. If one of these labels is too long and you don't set the number of lines to 0, the table view cell won't adjust its size.

Automotive answered 23/4, 2018 at 18:3 Comment(1)
Setting numberOfLines to 0 for both labels lets you get self-sizing with non-custom UITableViewCells. Many thanks!Gorgias
C
5

Forgot to remove tableView(heightForRowAt:indexPath:)

It could be the case that, like me, you accidentally forgot to remove the boilerplate code for the heightForRowAt method.

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 60.0
}
Cudbear answered 6/2, 2017 at 13:36 Comment(2)
... And of course do not give it a height constraint either ;-)Furtherance
You can return UITableViewAutomaticDimension in this method. For subclassingJezreel
I
5

For anyone that maybe faced the same problem with me: I struggled for an hour to make it work. A simple UIlabel with top, bottom left and right constraints. I used the willDisplayCell to pass the data to the cell and this was causing problems in cells height. As long as I put that code in cellForRow everything worked just fine. Didn't understand why this happened, maybe the cell height was calculated before willDisplayCell was called so there was no content to make the right calculation. I was just wanted to mention and probably help someone with the same problem.

Inclinatory answered 17/6, 2019 at 10:41 Comment(1)
Thank you! I too struggled over exactly this issue. Seems like a UIKit bug to me, but this solved it!Bonesetter
S
5

it was working for me fine in iOS 11 and above, while breaking in iOS 10 the solution was to add

table.rowHeight = UITableView.automaticDimension
table.estimatedRowHeight = 200 // a number and not UITableView.automaticDimension

also make sure you add "heightForRowAt" even if it works in iOS 11 and above, its needed if you support iOS 10

   func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
Stomato answered 7/8, 2019 at 13:1 Comment(0)
D
3

In my case i had two UITableViews, i had to modify this method as

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    CGFloat height = 0.0;
    if (tableView == self.tableviewComments) {
        return UITableViewAutomaticDimension;
    }else if (tableView == self.tableViewFriends) {
        height = 44.0;
    }
    return height;
}
Destined answered 3/1, 2017 at 17:35 Comment(0)
W
3

Try this, Simple solution it's work for me,

In viewDidLoad write this code,

-(void)viewDidLoad 
{
[super viewDidLoad];
 self.tableView.estimatedRowHeight = 100.0; // for example. Set your average height
 self.tableView.rowHeight = UITableViewAutomaticDimension;
}

In cellForRowAtIndexPath write this code,

 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
  static NSString *CellIdentifier = @"Cell";
  UITableViewCell *cell = [tableView 
  dequeueReusableCellWithIdentifier:CellIdentifier];
 if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
  }
    cell.textLabel.numberOfLines = 0; // Set label number of line to 0
    cell.textLabel.text=[[self.arForTable objectAtIndex:indexPath.row] valueForKey:@"menu"];
    [cell.textLabel sizeToFit]; //set size to fit 
    return cell;
 }
Woolridge answered 5/1, 2018 at 14:27 Comment(0)
L
1

For my setup, I first double checked the constraints in the Storyboard for the UITableViewCell were unambiguous top to bottom, and then had to modify code in 2 places.

  1. UITableViewDelegate's tableView(_:heightForRowAt:)

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
        // return UITableViewAutomaticDimension for older than Swift 4.2
    }
    
  2. UITableViewDelegate's tableView(_:estimatedHeightForRowAt:)

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
        // return UITableViewAutomaticDimension for older than Swift 4.2
    }
    

Step 1 and 2, lets you to apply autosizing just for particular rows. For applying to the whole UITableView, use:

tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = UITableView.automaticDimension
// return UITableViewAutomaticDimension for older than Swift 4.2
Latinist answered 4/12, 2018 at 10:38 Comment(0)
H
1

enter image description hereIn my case I did everything but it did not solve the problem for me, at last, I checked the lines of the label which was fixed to 3. Changing the line value to 0 solves the problem for me. so to tell you all it must be 0 and constraints Top, Bottom, Left, Right must be attached to work fine.

Heidy answered 3/12, 2020 at 17:10 Comment(1)
That's the perfect solution of making line count to 0Bonnibelle
G
1

An uncommon solution, but one that may save others time: in cellForRowAtIndexPath make sure there is no delay in setting your label text. For some unknown reason, I had it wrapped in a DispatchQueue.main.async block, and this meant that the cell was being returned before the label text was actually set, so the cell and label never expanded to the size of the text.

Gayden answered 15/12, 2021 at 12:42 Comment(0)
D
0

In order to make UITableViewAutomaticDimension to work, you need to make sure all 4 corners' constraints is added to the superview. In most case, it works well with UILabel, but sometimes i find UITextView does the trick when UILabel not working well at the time. So try to switch to UITextView and make sure Scrolling Enabled is unchecked in storyboard, or you can also set it programmatically.

Differential answered 17/10, 2017 at 11:53 Comment(0)
S
0

I had three horizontal items and the most left had a constraint to left, middle one had top, bottom, to the left item and to the right item. The right one had a right, and left to the middle item. The solution was to add additional left and right constraints to the middle item (my label) that were >= some number to the cell.

Superb answered 24/12, 2017 at 0:11 Comment(0)
S
0

Make sure all views in the cell are constrained to the Content View and not to the cell.

As apple says:

lay out the table view cell’s content within the cell’s content view. To define the cell’s height, you need an unbroken chain of constraints and views (with defined heights) to fill the area between the content view’s top edge and its bottom edge.

Shauna answered 13/1, 2018 at 7:12 Comment(0)
C
0

I've got a new solution..that's worked for me.

basically UITableViewAutomaticDimension renamed as UITableView.automaticDimension... I hope..it wo

Cunnilingus answered 15/5, 2019 at 2:21 Comment(0)
U
0

For recent version of ios and swift apple has changed the previously called UITableView.automaticDimension to UITableView().estimatedRowHeight, so to set the row height automatically use it like this: tableView.estimatedRowHeight = 150 //random estimate manually to help the compiler before setting the estimate value. tableView.rowHeight = UITableView().estimatedRowHeight

Underwent answered 16/1, 2022 at 2:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.