11

I am excited by the prospect of being able to build my static TableViews right within Xcode, using Auto Layout to support dynamic type, as mentioned in WWDC2014 What's New in Table and Collection Views.

I'd prefer to use strictly Xcode / Interface Builder and storyboards to handle the Auto Layout. When I do, somehow the TableView cells are not resizing and I'm sure I'm missing something simple.

To reproduce this, using Xcode 7 beta 5, I:

  • Created a new single view project.
  • Set the Storyboard entry point to a new UITableViewController.
  • Make it a static table view with grouped style.
  • Added a single label to the first row. Added constraints to the top, bottom, left, and right.
  • Set the label font to be "Body".
  • Added to ViewDidLoad:

    self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.estimatedRowHeight = 44.0;

  • Ran it and adjusted Dynamic Type in Settings. While the font changes, the TableView height remains stuck at the apparent default of 44 and truncates the label.

Truncated label in Simulator

Here is a GitHub repository which is the result of the above.

Why isn't Auto Layout causing the TableView to expand to fill the necessary space to fit the new larger label text?

I have found great posts on the subject such as the following, with a bent on using code to set up constraints here.

I'm not finding any examples of doing this in pure Interface Builder. Surely this is quite possible?

Update

I have updated the GitHub source to include a second table row with an ImageView instead of a UILabel; it shows the same issue:

Updated screenshot

Additionally, when I set an explicit height constraint on either the label or image view, I generate the following. The problem seems to be this "UIView-Encapsulated-Layout-Height" constraint which I have not set. I'm guessing it's generated because in my static tableview in IB, the Row Height is set (as default) to 44.

Unable to simultaneously satisfy constraints.
...

"<NSLayoutConstraint:0x7fa371f39e30 V:[UILabel:0x7fa371f38d30'Label'(20)]>",
"<NSLayoutConstraint:0x7fa371c39160 UILabel:0x7fa371f38d30'Label'.top == UITableViewCellContentView:0x7fa371e17dc0.topMargin>",
"<NSLayoutConstraint:0x7fa371c393c0 UITableViewCellContentView:0x7fa371e17dc0.bottomMargin == UILabel:0x7fa371f38d30'Label'.bottom>",
"<NSLayoutConstraint:0x7fa371f41a40 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7fa371e17dc0(43.5)]>"

But shouldn't this in ViewDidLoad be overriding this?

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0;

Do self-sizing table view cells simply not work with static table views?

Update 2

I have built the same thing using a dynamic prototype instead of a static table view, and all works fine:

enter image description here

It does indeed seem to be static versus dynamic prototyped tables. Static table view cells do not properly expand.

I've seen no mention of dynamic vs. static in the WWDC videos, so at this point I'm chalking this up to a bug. Will update if I learn anything new.

I have updated the GitHub repository above to show an example of both the static (broken) and dynamic (working) table views.

Community
  • 1
  • 1
John Stewart
  • 1,176
  • 1
  • 10
  • 22

3 Answers3

3

Answer:

This is a bug in Xcode7b5. I have just confirmed this by following the identical steps in Xcode 6.4 and Xcode 7b5.

  1. Create new Single View Application
  2. New File. Cocoa Class "MyStaticTableViewController", subclass of UITableViewController.
  3. In Storyboard, drag in new Table View Controller.
  4. Change Class to MyStaticTableViewController.
  5. Drag storyboard entry point to new VC.
  6. Delete original VC.
  7. Change Class to MyStaticTableViewController for new VC.
  8. Select the Table View. Change Content to Static Cells and Style to Grouped.
  9. Drag new label to first Table View Cell. Change Font to Body. Set top, bottom, left, right constraints to 0 and update frames.
  10. In MyStaticTableViewController.m, add:
 - (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.rowHeight = UITableViewAutomaticDimension;
    self.tableView.estimatedRowHeight = 44.0;

}
  1. Verify with Dynamic Type that increasing the size causes the table row to expand as well.

The project created by Xcode 6.4 works as expected - the table view cells expand to fit the label.

The project created by Xcode 7b5 fails as described in the original question.

Interestingly, if open the Xcode6 project with Xcode7, it works fine as well. It's something to do with how Xcode7 is creating the project, or storyboard.

Update

I compared the .storyboard files to each other, and in the broken Xcode7b5 one under the tableView entry, there is a rect defined:

<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>

I deleted this line and it seems that the table view cell now properly self-sizes!

Update 2

The key issue seems to be a "rect" entry left under each of the "tableViewCell" entries in the XML file. Whacking those is what fixes this issue.

Update 3

Filed radar:

"Engineering has determined that your bug report (22311571) is a duplicate of another issue (17995201) and will be closed."

John Stewart
  • 1,176
  • 1
  • 10
  • 22
  • That solved the problem in one of my projects, but in the other the cell still won't resize. Do you have any other idea? I am using Xcode 7. – Nick Podratz Sep 27 '15 at 17:00
  • Sorry, running this one down was my white whale. I would imagine the underlying XML file might still be screwed up if it was initially generated with a screwed up version of Xcode; might want to start over, if possible. – John Stewart Sep 28 '15 at 13:17
  • 2
    Mine didn't work until I also overrode `tableView:heightForRowAtIndexPath:` to return `UITableViewAutomaticDimension` – Pierre Houston Oct 14 '16 at 23:19
  • Overriding heightForRowAtIndexPath is all I needed to do to make this work in Xcode 8.3.2. Thanks @JohnStewart – Boon Jul 03 '17 at 20:41
1

I haven't got time to look at the code, but I'm almost sure the problem is the label. The font size changes but the size of the label doesn't. I'm suspecting that because the text is not being truncated after occupying the whole row, it's leaving a small margin.

Do a quick test: put a colored background to the text label. My bet is that you'll notice it's not growing. If it doesn't, take a look here: Adjust UILabel height depending on the text

Community
  • 1
  • 1
Bartserk
  • 675
  • 6
  • 18
  • Correct you are, Bartserk. Coloring the UILabel background confirms that the label is not expanding vertically to fit the text. I can see when I set a manual height constraint on the label that there that there are unsatisfiable constraints, including: `` - I think the answer is to find out where this constraint (UIView-Encapsulated-Layout-Height) is coming from! I'm betting somewhere in IB there is a checkbox I am missing. – John Stewart Aug 13 '15 at 17:34
  • After experimenting today, I don't believe the problem is with the label, but with the Content View. No matter what I do, there is a constraint `UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f8a8362e9e0(43.5)]>` - this seems to be due to the fact that in IB, the Row Height is set to 44. All of the examples I can find are about dynamic table views; this is static, and I wonder if this is the problem. I have updated GitHub link above with a version with the highlighted background, both for a label and an image view. Neither is "pushing" out the table view cell. – John Stewart Aug 13 '15 at 21:31
  • Hmm, that sounds funky. IB's pretty much changed since I last used it after jumping into programmatical interface hell, but yes, it looks like there's a constraint somewhere that's conflicting with the rest... – Bartserk Aug 14 '15 at 06:06
-1

For static table view cells you cannot use UITableViewAutomaticDimension inside of ViewDidLoad. Instead, use the override func heightForRowAt. I have nothing inside my viewDidLoad. I added these two override functions above ViewDidLoad.

//This first one overrides the height of each row so that it automatically resizes.

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

        return UITableViewAutomaticDimension

    }

//This gives an estimate of the height of the rows before resizing

    override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {

        return 100
    }

As long as you have top, bottom, left and right layout constraints, everything should resize.

Eric Duffett
  • 1,654
  • 17
  • 25