Nick S.
Nick S.

Reputation: 2233

NSAutoResizingMaskLayoutConstraint error when resizing cell upon selection

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?

Upvotes: 2

Views: 3072

Answers (1)

Nick S.
Nick S.

Reputation: 2233

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.

Upvotes: 6

Related Questions