CaffeineShots
CaffeineShots

Reputation: 2162

why UITableViewAutomaticDimension not working?

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

Upvotes: 83

Views: 84637

Answers (19)

Nathenael Tarek
Nathenael Tarek

Reputation: 167

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

Upvotes: 0

alstr
alstr

Reputation: 1556

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.

Upvotes: 1

MALIKK HABIB UR REHMAN
MALIKK HABIB UR REHMAN

Reputation: 880

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.

Upvotes: 1

Bassant Ashraf
Bassant Ashraf

Reputation: 1609

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
    }

Upvotes: 5

Thomas
Thomas

Reputation: 177

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.

Upvotes: 5

Yeasir Arafat Aronno
Yeasir Arafat Aronno

Reputation: 11

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

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

Upvotes: 0

Pranav Kasetti
Pranav Kasetti

Reputation: 9915

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

Upvotes: 1

Krunal
Krunal

Reputation: 79636

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.

Upvotes: 28

Zampano
Zampano

Reputation: 101

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.

Upvotes: 7

Badr Bujbara
Badr Bujbara

Reputation: 8671

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.

Upvotes: 0

Jaywant Khedkar
Jaywant Khedkar

Reputation: 6111

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;
 }

Upvotes: 3

Darko
Darko

Reputation: 615

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.

Upvotes: 0

Terry Tan
Terry Tan

Reputation: 441

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.

Upvotes: 0

Guy Daher
Guy Daher

Reputation: 5601

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
}

Upvotes: 5

Bptstmlgt
Bptstmlgt

Reputation: 127

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!

Upvotes: 7

M.Yessir
M.Yessir

Reputation: 222

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;
}

Upvotes: 3

Eyeball
Eyeball

Reputation: 3307

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!

Upvotes: 33

CamQuest
CamQuest

Reputation: 863

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.

Upvotes: 20

Zell B.
Zell B.

Reputation: 10286

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

Upvotes: 175

Related Questions