2

I am implementing a custom UITableView which will expand a single cell vertically to show details when a user taps the cell.

I am encountering an issue when I call addConstraint to a UITableViewCell in the didSelectRowAtIndexPath handler:

Unable to simultaneously satisfy constraints.
...
If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0xa0c9cc0 V:[UITableView:0xc339c00]-(0)-|   (Names: '|':UITableViewCellContentView:0xa0c8910 )>",
    "<NSAutoresizingMaskLayoutConstraint:0xa0b8600 h=--& v=--& V:[UITableViewCellContentView:0xa0c8910(25)]>",
    "<NSLayoutConstraint:0xa0caad0 V:|-(42)-[UITableView:0xc339c00]   (Names: '|':UITableViewCellContentView:0xa0c8910 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xa0c9cc0 V:[UITableView:0xc339c00]-(0)-|   (Names: '|':UITableViewCellContentView:0xa0c8910 )>  

Here are some more details on my implementation:

  1. When a user selects a cell, didSelectRowAtIndexPath is called in my subclassed UITableView where I update a member named selectedRowIndex.
  2. Also in didSelectRowAtIndexPath, I call addConstraint on a cell (which I retrieve via [tableView cellForRowAtIndexPath:indexPath]). This is a vertical constraint: "V:|-(42)-[embeddedTableView]", which ensures that there is space above another embedded table within the cell's detail view.
  3. After didSelectRowAtIndexPath is complete, heightForRowAtIndex is called. My implementation of heightForRowAtIndex will check the selectedRowIndex value and return a larger height for the selected row.

At step 2, the above "Unable to simultaneously satisfy constraints" error occurs. I believe that this is because didSelectRowAtIndexPath is called before heightForRowAtIndex. My hunch is the translatesAutoresizingMaskIntoConstraints setting (which is YES in my implementation) is creating new constraints based the runtime value of the cell height, which is updated after the didSelectRowAtIndexPath code is run.

Is there a recommended way to resolve this issue? Or is there an alternative approach to performing the cell expansion which would still allow me to set necessary cell constraints for the cell's content?

Nick S.
  • 2,203
  • 3
  • 19
  • 21
  • What constraint are you trying to add when you expand the cell? You need to describe what constraints you have before expansion, and what you're trying to change. – rdelmar Sep 14 '14 at 05:26
  • Added the constraint being added to step 2: "V:|-(42)-[embeddedTableView]". – Nick S. Sep 14 '14 at 06:15
  • Also worth noting is the NSAutoresizingMaskLayoutConstraint (UITableViewCellContentView(25)) listed in the the outputted conflicts. The value of 25 appears to be coming from the original cell height (before expansion) - as calculated/returned from an earlier invocation of heightForRowAtIndexPath. – Nick S. Sep 14 '14 at 06:35
  • It's hard to tell what is going on without knowing all the constraints you have in your cell. Also, you say that translatesAutoresizingMaskIntoConstraints is set to YES. Set to YES for what view? Are you adding views to your cell in code? – rdelmar Sep 14 '14 at 15:51
  • translatesAutoresizingMaskIntoConstraints is set to YES (default) for all of my views. – Nick S. Sep 14 '14 at 18:07
  • Also, the only programmatic constraint i am adding is V:|-(42)-[embeddedTableView]. I am not adding views to my cell in code (just unhiding them - details are in the cell prototype). – Nick S. Sep 14 '14 at 18:15
  • I believe the problem is concisely this: I'm calling addConstraint to constrain the enlarged version of the cell (25px which is the unexpanded height) in didSelectRowAtIndexPath - but 42px+ is going to be larger than the automatic 25px constraint which is still in effect before heightForRowAtIndexPath gets called (step 3). Is there a way I could invoke the expansion code AFTER heightForRowAtIndexPath is run? – Nick S. Sep 14 '14 at 18:22

1 Answers1

6

Figured it out. Part of my problem was related to the resolution here: How is it possible that UITableViewCellContentView height is different from heightForRowAtIndexPath:

I found that I needed to add [self.contentView setAutoresizingMask:UIViewAutoresizingFlexibleHeight] in the cell's subclassed awakeFromNib to allow for my cell's height to be resized.

This wasn't the whole fix, though. After doing some reading, I found the answer to my other question related to calling addConstraint before heightForRowAtIndex was called. My suspicion was correct that it was problematic to call addConstraint in didSelectRowAtIndexPath.

Per the UIView Class Reference, the correct way to add the constraint was for me to call - (void)setNeedsUpdateConstraints in didSelectRowAtIndexPath. This causes an invocation of updateConstraints, which is the function I must implement for custom constraint updates.

Community
  • 1
  • 1
Nick S.
  • 2,203
  • 3
  • 19
  • 21