26

When the Table View is first loaded, all of the visible cells are the estimatedRowHeight. As I scroll down, the cells are being automatically sized properly, and when I scroll back up the cells that were initially estimatedRowHeight are being automatically sized properly.

Once the cells are being automatically sized, they don't ever seem to go back to being the estimatedRowHeight.

override func viewDidLoad() {
    super.viewDidLoad()
    self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .Plain, target: nil, action: nil)
    self.tableView.estimatedRowHeight = 80.0
    self.tableView.rowHeight = UITableViewAutomaticDimension

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem()
}

and

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cellIdentifier = "Cell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as CustomTableViewCell

    // Configure the cell...
    let restaurant = restaurants[indexPath.row]
    cell.namelabel.text = restaurant.name
    cell.locationlabel.text = restaurant.location
    cell.typelabel.text = restaurant.type
    cell.thumbnailImageView.image = UIImage(named: restaurant.image)
    cell.thumbnailImageView.layer.cornerRadius = cell.thumbnailImageView.frame.size.width / 2
    cell.thumbnailImageView.clipsToBounds = true
    cell.accessoryType = restaurant.isVisited ? .Checkmark : .None

    return cell
}

Thoughts on how to have the cells autoresize initially?

UPDATE: As of Xcode 7 beta 6 this is no longer an issue

jjatie
  • 5,152
  • 5
  • 34
  • 56
  • Also to note, my AutoLayout constraints are properly set (triple checked) – jjatie Jan 27 '15 at 14:58
  • I am having a similar issue. I can resolve it without reloading table sections by making the constraint that controls the height of the tableCell - in my case the constraint that pins the content view bottomMarginTop to the textView bottom to 1000 priority. Even though this causes an unsatisfiable constraints error, the end result is that the table view cells are displayed properly. – nwales Mar 16 '15 at 20:10
  • 1
    this is still an issue in Xcode 9.2 – Julius Feb 06 '18 at 16:57

11 Answers11

27

Just call "reloadSections" after your Table is loaded:

self.tableView.reloadSections(NSIndexSet(indexesInRange: NSMakeRange(0, self.tableView.numberOfSections())), withRowAnimation: .None)

Or in Swift 3:

let range = Range(uncheckedBounds: (lower: 0, upper: self.tableView.numberOfSections))
self.tableView.reloadSections(IndexSet(integersIn: range), with: .none)
Bart van Kuik
  • 4,704
  • 1
  • 33
  • 57
Blank
  • 4,872
  • 2
  • 28
  • 25
  • 4
    This is a solution, however it shouldn't be necessary. – jjatie Feb 03 '15 at 16:58
  • 1
    This is wrong answer, you should find a mistake in your constraints or code – Nosov Pavel Apr 06 '15 at 07:19
  • I don't think this answer ist "wrong" ;) But yes, with the correct usage of constraints, it isn't be necessary... Unfortunately constraints sometimes aren't that intuitive as they should be. Especially in combination with the Storyboard. – Blank Apr 15 '15 at 10:01
  • 3
    Sadly even thought I have rebuilt my own constraint at least 5 times now, I'm starting to think that it's a bug in Apple's implementation of UITableViewAutomaticDimension. It seems to auto-add height constraints that makes the cell expand or shrink and when reusing a cell it then works... – Marc-Alexandre Bérubé May 11 '15 at 15:11
  • I also find the above code working, i also tried resetting my constraints couple of times but still its not working :( – vinbhai4u Jun 01 '15 at 09:23
  • @NosovPavel No one seems to be able to take your advice and set their constraints to fix the problem. I have the same situation as everyone else, with my cells condensed until scrolled. Now my constraints clearly state top-bottom distances to cell top/bottom and between all views in the cell. I do not have explicit heights on my labels, as my label heights should change based on content. Since no one can fix their constraints properly, can you leave a comment with a few ideas as to what we need to do to properly layout the cell? – Dave G Sep 09 '15 at 06:43
  • In which method should I add this line to? – Oded Regev Feb 04 '16 at 12:41
  • What worked for me was adding this in the `-viewWillLayoutSubviews` of the UIViewController that contains the table. Thanks so much, Blankarsch! --- Code I'm currently working in is Objective C, where this looks as follows: `[self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.tableView.numberOfSections)] withRowAnimation:UITableViewRowAnimationNone];` – Erik van der Neut Mar 24 '16 at 06:28
  • 1
    Added Swift 3 version. Thanks @blankarsch – Bart van Kuik Jan 18 '17 at 15:56
  • 1
    Note: You have to reload the sections BEFORE calling reloadData – MobileMon Jul 28 '17 at 14:34
  • Not sure why it's deemed necessary to call `reloadSections` when you could just call `reloadData` and it has the same effect. – shim Feb 23 '18 at 19:08
  • Note while `reloadData` worked for me in one spot, I encountered a similar issue where neither `reloadData` nor `reloadSections` is working, so now I'm confused. I am using default `UITableViewCell` instances (i.e. not customized) in a `UIViewController` with a `UITableView` property (I haven't seen the same issue yet in a `UITableViewController`). – shim Mar 01 '18 at 20:01
8

I ran into the same issue and found out that the accessory cell.accessoryType messes with this automatic resizing when it is not None, so it seems like a bug in Xcode at the moment.

But as @Blankarsch mentioned, calling reloadSections(..) helps to fix this issue if you need to have an accessory.

Accessory to "None" solved my issue

shim
  • 9,289
  • 12
  • 69
  • 108
eule
  • 571
  • 6
  • 9
8

I think the answers over here have fewer side effects. Specifically adding cell.layoutIfNeeded() in tableView:cellForRowAtIndexPath:

I'm also doing what @nosov suggests as is good practice, but haven't tested if they need to be done in tandem.

Community
  • 1
  • 1
rob5408
  • 2,972
  • 2
  • 40
  • 53
  • This solved my problem when my UILabel's contents were only few pixels wider than available space (before it would sometimes resize properly if I scrolled cell out of view and back). – frin Sep 04 '15 at 12:19
5

just override estimatedHeightForRowAtIndexPath like this

(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewAutomaticDimension;
}

and check your autoLayout constraints in CustomTableViewCell view.

Nosov Pavel
  • 1,571
  • 1
  • 18
  • 34
1

Just make sure that your labels don't have an explicit content size set at Interface Builder. They must be Automatic like the screenshot below for the Automatic Row height to work properly without the need to reload any sections up front.

enter image description here

David H.
  • 2,762
  • 1
  • 24
  • 18
  • Try to delete the self.tableView.estimatedRowHeight = 80.0 line on the viewDidLoad method. Does it work? – David H. Feb 05 '15 at 21:46
  • It does! I've played with the values for estimatedRowHeight between 1 and 120, but with no success. I worry that in larger data sets with more variation in cell size that scrolling performance would be harmed without having the estimatedRowHeight attribute set to something reasonable. – jjatie Feb 06 '15 at 14:02
1

If you set your constraints based on the cell itself (instead of cell content view), the table is not able to get the proper size. So, to fix this issue, your constraints must be set to the content view.

However, this is problem when your cells supports both configuration with/without accessory view. In that case, the content view gets resized according to the accessory view, and the result may not the the expected by the user. So, in this case, a solution is setting 2 constraints, one to the cell and a second one with lower priority to the cell content view.

Pablo A.
  • 2,042
  • 1
  • 17
  • 27
0
func tableView(_ tableView: UITableView, 
  cellForRowAt indexPath: IndexPath) -> UITableViewCell


- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath;

In the function set the cell with the preferred content, in order for UITableViewAutomaticDimension to work flawlessly.

The problem is caused because the cell content is loaded in some other delegate function, so you can see that cells automatically resize to the required size.

  • While this may be the case, it did not solve the problem at the time. There was a bug in the SDK which seems to be resolved now; my bug report was closed as a duplicate. – jjatie Sep 30 '16 at 15:30
0

Make sure to init your cell in tableView:cellForRowAt:. I've run into this issue even with Xcode 8 when I was setting cell content in tableView:willDisplay:forRowAt:

Miroslav Hrivik
  • 822
  • 13
  • 16
0

For me I only have this problem when using willDisplay cell to set the text of my labels

If I set the text of my labels in cellForRowAt index path, everything is fine

MobileMon
  • 8,341
  • 5
  • 56
  • 75
0

For me what solved it was the combination of @[David Hernandez] answer. enter image description here

Removed the selection from above, and in Cell's layoutSubviews I set the preferredMaxLayoutWidth as this (change 30 to your desired left right spacing)

-(void) layoutSubviews {
    [super layoutSubviews];
    self.textDescriptionLabel.preferredMaxLayoutWidth = self.frame.size.width - 30;
}
Kamran Khan
  • 1,367
  • 1
  • 15
  • 19
0

Xcode 9.3, Swift 4.1 adding

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

in addition to

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

worked for me.