UITableViewCell with unsatisfiable constraint

367 Views Asked by At

I have a custom UITableViewCell that is laying out exactly like I want it to, but it throws an unsatisfiable constraint error:

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:0x165af570 V:|-(10)-[UIButton:0x167d1bb0'Scan Patient Bracelet Squ...']   (Names: '|':UIView:0x167d1b20 )>",
"<NSLayoutConstraint:0x165af5d0 V:[UIView:0x1652b420]-(0)-|   (Names: '|':UIView:0x167d1b20 )>",
"<NSLayoutConstraint:0x165f7de0 UIView:0x1652b420.bottom == UIButton:0x167d1bb0'Scan Patient Bracelet Squ...'.bottom + 10>",
"<NSLayoutConstraint:0x165df2d0 V:[UIView:0x167d1b20]-(0)-|   (Names: '|':CMBarcodeScanCell:0x16b88800 )>",
"<NSLayoutConstraint:0x165df300 V:|-(0)-[UIView:0x167d1b20]   (Names: '|':CMBarcodeScanCell:0x16b88800 )>",
"<NSLayoutConstraint:0x167d1540 V:[CMBarcodeScanCell:0x16b88800(1)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x15fe1730 UIButton:0x15d38490'Scan Patient Bracelet Squ...'.bottom == UIView:0x15ff5750.bottom - 10>

I can't figure out which is the offending constraint. The constraints can be traced from the top to the bottom and from side to side.

Any hints?

EDIT

After some more fiddling, I have it down to just these three constraints:

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:0x1478f570 UIButton:0x1475ef00'Scan Patient Bracelet Squ...'.bottom == UITableViewCellContentView:0x1476e930.bottomMargin>",
    "<NSLayoutConstraint:0x1478f5a0 UIButton:0x1475ef00'Scan Patient Bracelet Squ...'.top == UITableViewCellContentView:0x1476e930.topMargin>",
    "<NSLayoutConstraint:0x147aeb00 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x1476e930(1)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x1478f570 UIButton:0x1475ef00'Scan Patient Bracelet Squ...'.bottom == UITableViewCellContentView:0x1476e930.bottomMargin>

The third constraint of UIView-Encapsulated-Layout-Height of 1 is not in the design, as you can see here:

interface builder screen shot

but now the layout is no longer correct. The button text extends above and below the cell content view.

screen shot

The problem appears to be button content size is not being computed based on label content size.

Debugger view of UIButton for scan button:

uibutton sizing

Debugger view of UIButton text label:

uibutton label sizing

I don't know how UIButton computes its content size, but it isn't working in this case. So now I have 2 problems, the constraint conflict and the cell layout.

FINAL EDIT

The conflict was coming from a hack I was using to make the cells resize and layout for variable button text. It was in heightForRowAtIndexPath:

cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tTblView.bounds), 1);
cell.contentView.bounds = cell.bounds;
[cell layoutIfNeeded];

This did make cells layout as desired, but introduced a constraint for contentView height of 1 and created the conflict above.

I also experimented with using CGFLOAT_MAX instead of 1, but that produced an error message as well at runtime.

 cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tTblView.bounds), CGFLOAT_MAX);
cell.contentView.bounds = cell.bounds;
[cell layoutIfNeeded];

So I'm closing this and working on my auto layout constraints until I can get the correct layouts without introducing such hack code or causing constraint conflicts.

2

There are 2 best solutions below

8
On BEST ANSWER

The constraints can be traced from the top to the bottom and from side to side.

The issue here is purely top-to-bottom, as you may easily see by studying the contraints. Let's just consider these three constraints:

V:[UIView:0x167d1b20]-(0)-| (Names: '|':CMBarcodeScanCell:0x16b88800 )
V:|-(0)-[UIView:0x167d1b20] (Names: '|':CMBarcodeScanCell:0x16b88800 )
V:[CMBarcodeScanCell:0x16b88800(1)]

So the top and bottom of view 0x167 are pinned right to the top and bottom of the CMBarcodeScanCell - but then you come along with an absolute height constraint that says the CMBarcodeScanCell is just 1 pixel tall? That sounds like a recipe for trouble right there.

0
On

As shown in the final edit section of the posted question, the problem was not in the cell but in the hack code that I had in heightForRowAtIndexPath of the table view controller.

cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tTblView.bounds), 1);
cell.contentView.bounds = cell.bounds;
[cell layoutIfNeeded];

Setting the bounds height to 1 introduced the conflicting constraint. Even though it made my cells layout correctly, this is clearly not good and I just need to find the correct way to do this.