简体   繁体   中英

UITableViewCell: unable to simultaneously satisfy constraints

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 (ie, 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?

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:

  1. Just add another layout constraint to the content view constraining it to your desired height of 592 points.

  2. Then remove the delegate methods for tableView:estimatedHeightForRowAtIndexPath and tableView:heightForRowAtIndexPath entirely.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM