0
votes

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

1
I haven't read the whole post yet, but I have to ask: why're you using UITableView here?Arek Holko
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...Khanh Nguyen
@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.Johann Fradj
@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 ;-)... lolJohann Fradj

1 Answers

1
votes

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).