Reputation: 11598
I've got a UITableViewCell
that I'm creating, and I am using auto layout with constraints constructed entirely in code.
While the actual output in the app is fine (i.e., it looks just as I have designed it to look), I am getting the famous "Unable to simultaneously satisfy constraints" error/warning message.
Here is the list of constraints printed by the error message:
"<NSLayoutConstraint:0x7fb2f280e5e0 V:|-(0)-[UIScrollView:0x7fb2f0435730] (Names: '|':UITableViewCellContentView:0x7fb2f04345c0 )>",
"<NSLayoutConstraint:0x7fb2f280e880 V:[UIScrollView:0x7fb2f0435730(280)]>",
"<NSLayoutConstraint:0x7fb2f280e630 V:[UIScrollView:0x7fb2f0435730]-(16)-[UIScrollView:0x7fb2f04360d0]>",
"<NSLayoutConstraint:0x7fb2f280e920 V:[UIScrollView:0x7fb2f04360d0(140)]>",
"<NSLayoutConstraint:0x7fb2f280e970 V:[UIScrollView:0x7fb2f04360d0]-(16)-[SummaryView:0x7fb2f0436c20]>",
"<NSLayoutConstraint:0x7fb2f280e9f0 V:[SummaryView:0x7fb2f0436c20(140)]>",
"<NSLayoutConstraint:0x7fb2f280e8d0 V:[SummaryView:0x7fb2f0436c20]-(0)-| (Names: '|':UITableViewCellContentView:0x7fb2f04345c0 )>",
"<NSLayoutConstraint:0x7fb2f0439e30 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7fb2f04345c0(44)]>"
Every single one of them is completely correct and exactly what I wanted except for the last one. That one is quite clearly system generated. 44 points is (I believe) the system-standard cell height. What's curious to me is that I have explicitly stated a correct cell height (in this case, 592 points). Here is what I have done in my UITableViewController
subclass:
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [TableViewCell heightNeededForCell];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [TableViewCell heightNeededForCell];
}
I think the reason this is happening is because of my cell's init
function:
#pragma mark - Table View Cell Lifecycle
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self != nil) {
[self setupUserInterface];
}
return self;
}
#pragma mark - UI Setup
- (void)setupUserInterface {
[self createControls];
[self createConstants];
[self setupControls];
[self layoutControls];
[self.contentView layoutIfNeeded]; <-- Here's where the warning occurs
// The UIScrollViews (which contain UIImageViews) were not
// adjusting their contentSize properly, so I do it manually here
self.scrollView1.contentSize = self.heartImageView1.bounds.size;
self.scrollView2.contentSize = self.heartImageView2.bounds.size;
}
}
From my results, it appears that I can safely ignore this error, but I'm kinda picky and don't like the fact that I'm getting a warning, even if I can explain it and it doesn't appear to cause any trouble. How would I successfully change the system-supplied constraint?
Upvotes: 1
Views: 2707
Reputation: 28094
You're right that the unexpected constraint is coming from the UITableView
machinery itself.
I think when you call layoutIfNeeded
in the initializer, you are confusing the UITableView
machinery which expects to be responsible for doing layout on the cell as a whole, and for ensuring that the cell wraps its own contentView
correctly. So you've told contentView
to layout, but the cell itself has not been told to layout in tandem at the right time. What is the right time? Only UITableView
knows its own secrets...
There's probably more than one way to workaround the problem but what I'd suggest is to switch to using self-sizing cells. That way you'd be taking responsibility for exactly what UITableView
expects you to handle, leaving less room for surprises. Since you're already defining the cell's layout with Auto Layout, you're almost there already.
Here's how to do it:
Just add another layout constraint to the content view constraining it to your desired height of 592 points.
Then remove the delegate methods for tableView:estimatedHeightForRowAtIndexPath
and tableView:heightForRowAtIndexPath
entirely.
Then set tableView.estimatedRowHeight = 600
(or any value, actually) in viewDidLoad
.
Now the tableView will set the cells to the height 592, which is the height that the cells themselves declare that they prefer via their own Auto Layout constraints.
There are some examples of numerous ways to do this here: https://github.com/algal/TableViewSpike.
Note: Self-sizing cells requires a deployment target of iOS 8.0 or above.
Upvotes: 4