I have a UITableViewSubclass (style: UITableViewCellStyleValue1) that has a custom label that is essentially a replacement for the normal textLabel
label. It should be left aligned with the normal textLabel
but has a width to end 8 points to the left of the normal detailTextLabel
. I get the desired effect, but when the cells are used, an exception is thrown about being unable to satisfy the constraints simultaneously.
What I don't understand is why it complains, there is no apparent conflict. Calling [self layoutIfNeeded] after setting up the constraints silences the exception. Alternatively, lowering the priority of the constraint that configures the trailing property (for example, UILayoutPriorityDefaultHigh
instead of the default UILayoutPriorityRequired
) also silences the exception, obviously because I'm informing the Auto Layout engine that it's okay to break/ignore that constraint.
I'm assuming that the standard UITableView implementation maybe oddly lays out the textLabel
and textLabel
in a fashion that makes it initially impossible to describe the view described. For example, if the textLabel
was actually placed on the right side of the cell and detailTextLabel
was placed on the left side, then the layout I've described would be impossible.
When does Auto Layout take effect, in the context of this scenario. Is it jumping the gun and attempting to layout things before it's supposed to?
No Storyboards or XIBs are being used. Purely code based.
#import "EBTStoreTableViewCell.h"
@interface EBTStoreTableViewCell ()
@property (nonatomic, readonly, weak) UILabel *storeNameLabel;
@end
@implementation EBTStoreTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier];
if (self) {
self.textLabel.text = @" ";
self.detailTextLabel.text = @" ";
UILabel *storeNameLabel = [[UILabel alloc] init];
storeNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
[storeNameLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow forAxis:UILayoutConstraintAxisHorizontal];
[self.contentView addSubview:storeNameLabel];
_storeNameLabel = storeNameLabel;
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:storeNameLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.textLabel attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.0f]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:storeNameLabel attribute:NSLayoutAttributeBaseline relatedBy:NSLayoutRelationEqual toItem:self.textLabel attribute:NSLayoutAttributeBaseline multiplier:1.0f constant:0.0f]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:storeNameLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.detailTextLabel attribute:NSLayoutAttributeLeading multiplier:1.0f constant:-8.0f]];
// [self layoutIfNeeded]; // doing this makes the issue go away
}
return self;
}
// Setters ommited
@end
This the exception message I get:
2014-04-23 11:50:42.092 Application[32507:60b] 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:0xde03910 UILabel:0xde036b0.leading == UILabel:0xde00590.leading>",
"<NSLayoutConstraint:0xde03a30 UILabel:0xde036b0.trailing == UITableViewLabel:0xde00c10.leading - 8>",
"<NSAutoresizingMaskLayoutConstraint:0xde01920 h=--& v=--& UILabel:0xde00590.midX ==>",
"<NSAutoresizingMaskLayoutConstraint:0xde1de50 h=--& v=--& H:[UILabel:0xde00590(0)]>",
"<NSAutoresizingMaskLayoutConstraint:0x17f50a10 h=--& v=--& UITableViewLabel:0xde00c10.midX ==>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0xde03a30 UILabel:0xde036b0.trailing == UITableViewLabel:0xde00c10.leading - 8>
Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.