0

I'm working on an iPad app which is handling portrait and landscape orientations. I've a tableview displaying cells with a complex (?) layout and which can have differents height.

Here's a screenshot of what it should look like in portrait (= 768 pts witdh, which should result in a 435 pts height) Portrait simulation

Here's a screenshot of what it should look like in landscape (= 1024 pts width, which should result in a 526 pts height) Landscape simulation

To simplify a little bit the layout we'll keep only the first image.

Layout

I've 1 image which should keep its ratio while growing/decreasing on device rotation: in portrait = 256 width * 342 height in landscape = 341,333 width * 456 height And I've the yellow view (which should has a margin of 8 pts and a padding of 16 pts in each directions) containing a title (in blue) and a potential multiline text content (in pink). Notes: - the pink label could be totally empty. - the yellow view will be textured that's why it's needed, it's not just an extra view to workaround something.

Content View (child of UITableViewCell) Constraints

V:|-(0)-[UIImageView]   (Names: '|':UITableViewCellContentView)>",   // Top margin (0 pts) of the image
H:|-(0)-[UIImageView]   (Names: '|':UITableViewCellContentView)>",   // Left margin (0 pts) of the image
V:[UIImageView]-(8)-[UIView]>",     // Vertical space (8 pts) between the image and the yellow view (i.e. top margin of the yellow view)
H:|-(8)-[UIView]   (Names: '|':UITableViewCellContentView)>",   // Left margin (8 pts) of the yellow view
H:[UIView]-(8)-|   (Names: '|':UITableViewCellContentView)>",   // Right margin (8 pts) of the yellow view
V:[UIView]-(8)-|   (Names: '|':UITableViewCellContentView)>",   // Bottom margin (8 pts) of the yellow view

Yellow View Constraints

V:|-(16)-[UILabel:Blue]   (Names: '|':Yellow View )>",   // Top margin (16 pts) of the blue label (i.e. top padding of the yellow view)
H:|-(16)-[UILabel:Blue]   (Names: '|':Yellow View )>",   // Left margin (16 pts) of the blue label
V:[UILabel:Blue]-(>=16)-|   (Names: '|':Yellow View )>",   // Bottom margin (>= 16 pts) of the blue label
H:[UILabel:Blue]-(NSSpace(8))-[UILabel:Pink]>",   // Horizontal space between blue and pink labels
V:[UILabel:Pink]-(16)-|   (Names: '|':Yellow View )>",   // Top margin (16 pts) of the pink label
H:[UILabel:Pink]-(16)-|   (Names: '|':Yellow View )>",   // Right margin (16 pts) of the pink label
V:|-(16)-[UILabel:Pink]   (Names: '|':Yellow View )>",   // Bottom margin (16 pts) of the pink label

Constraints notes

  • In Interface Builder I've setup a place holder intrinsic size of 256 width * 342 height for the image (We'll see later that I set real size constraints in code dynamically depending on device orientation)
  • The blue label has an horizontal content compression priorrity of 751
  • The image has a vertical hugging priority of 1
  • The yellow view and the pink label a vertical hugging priority of 1000

Interface Builder Tests

If I increase the cell height, the image is deformed and it's height increase while the yellow view stick on the bottom whitout being deformed. So everything is ok (since we can't setup proportional constraints in IB to mimic the keeping ratio growing of the image).

Code

available on GitHub

Results

If I launch the app in portrait, the cells are perfect. The pink label is displayed on 2 lines, each sizes and spacing are fully respected/calculated! If then I rotate to landscape, the image doesn't grow and instead it's the yellow view and the pink label which are growing... Here's a screenshot: Landscape version when rotating from portrait

Now If I launch the app in landscape, the cells are perfect too. The image is well sized (351 pts width (rounded value) * 456 pts heigth), etc... If then I rotate to portrait it makes the app to crash... With the following output:

Unable to simultaneously satisfy constraints.
     Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0xa3d9dd0 V:|-(0)-[UIImageView]   (Names: '|':UITableViewCellContentView )>",
    "<NSLayoutConstraint:0xa3d9e00 V:[UIView]-(8)-|   (Names: '|':UITableViewCellContentView )>",
    "<NSLayoutConstraint:0xa3d9e60 V:[UIImageView]-(8)-[UIView]>",
    "<NSLayoutConstraint:0xa3dd9b0 V:[UIImageView(456)]>",
    "<NSAutoresizingMaskLayoutConstraint:0xa3de670 h=--& v=--& V:[UITableViewCellContentView(431)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xa3dd9b0 V:[UIImageView(456)]>

Note: UIView is the yellow view

Thanks a lot for your help (or a least reading ;-)

PS: I've post the same question on dev forums yesterday and will post any progress here. DevForum discussion link

4
  • 1
    I haven't read the whole post yet, but I have to ask: why're you using UITableView here?
    – Arek Holko
    Commented Oct 25, 2013 at 9:41
  • 1
    Appreciate your effort in typing the whole thing here... but it's better if you can somehow nail down you problem in fewer lines, e.g. by extracting the key issue you are having, ripping away all the irrelevant details. I am not sure how many would go thru all this, and I doubt that the answer will help anyone else other than you. @ArkadiuszHolko raised a good point thought... Commented Oct 25, 2013 at 10:01
  • @ArkadiuszHolko, Because I'm displaying a list of cells like that. Do you mean that I should use a CollectionView? I tried and it was worst ;-). BTW in the code I return only 1 section and 1 row for debugging purpose, otherwise I really want to display dozen of cells. Commented Oct 25, 2013 at 19:09
  • @KhanhNguyen I've reduce a little bit the size of the post. I understand but on the other hand I'm sure that it will help people focus on the exact issue. Also I wanted to make a post 3 times longer (explaining all the ways I've tried ;-)... lol Commented Oct 25, 2013 at 19:23

1 Answer 1

1

I downloaded your sample project and ran it. You seem to have a few issues in the code, but so far the most obvious one was that you are not calling reloadData on the table view when an autorotation occurs -- this is required in order to have the table view recalculate the cell heights (and re-layout each visible cell based on the change).

Add the below method to your ARJProcedureListViewController.m file:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    [self.tableView reloadData];
}

I am seeing constraint conflicts logged to the console still, which means at least one of your constraints is wrong (you are probably over-constraining some view).

4
  • I didn't thought it was needed since if you put a breakpoint on the method - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath, you'll see that it is called on rotation and before crashing. Moreover it's returning the good computed height. I've tried and it seems to work (except that the animation isn't perfect (the cell seems to be deformed, it's not critical at all ;-). I've never ever called a reloadData on tableView when rotation occurred! I made thousands of screens that never had this issue but I wasn't using Auto Layout... Commented Oct 25, 2013 at 19:17
  • Well all I can say is that I see different things after rotating with and without the above call to reloadData :) Perhaps it's probably triggering a call to setNeedsLayout which will cause your constraints to be re-evaluated, resulting in a different appearance. Anyways, there is definitely still an issue with your constraints so I would focus your effort on finding the issue there.
    – smileyborg
    Commented Oct 25, 2013 at 19:31
  • I used your code and it works here... It seems that I didn't made any local modification that the code you used (from GitHub). Also, like you, I think the reload data is a workaround and not really needed... Commented Oct 25, 2013 at 19:42
  • Someone suggest me to call setNeedsUpdateConstraints instead of reloadData. The layout broken back to my first result with a good animation ;-). It's getting me crazy. Commented Oct 28, 2013 at 6:23

Not the answer you're looking for? Browse other questions tagged or ask your own question.