我有一个自定义的UITableViewCell,我正在尝试使用rewiews加载。流程是:我从单元格的contentView(setWithLoadingState方法)中的UIActivityIndicator开始,在我从API返回响应后,我设置了带有注释/错误消息的单元格(setWithErrorMessage:/ setWithReviews :)。当我尝试使用评论设置单元格时出现问题(setWithReviews:method)。
此外,该单元格是IB中的静态单元格。
问题在于,有时布局确实是错误的,我无法弄清楚原因。控制台还警告我关于不可满足的约束,但据我所知,这可能是由于UITableView在beginUpdates和endUpdates之间制作的动画。
控制台消息(错误多次出现。):
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)
(
"<NSAutoresizingMaskLayoutConstraint:0xbc32930 h=--& v=--& V:[UITableViewCellContentView:0xbcd3330(40.5)]>",
"<NSLayoutConstraint:0xbed2820 V:|-(NSSpace(20))-[UIView:0xbecc350] (Names: '|':UITableViewCellContentView:0xbcd3330 )>",
"<NSLayoutConstraint:0xbcb8540 V:[UIView:0xbecc350]-(NSSpace(8))-[UIView:0xbec7870]>",
"<NSLayoutConstraint:0xbcb8fe0 V:[UIView:0xbec7870(0.5)]>",
"<NSLayoutConstraint:0xbc24e00 V:[UIView:0xbec7870]-(NSSpace(8))-[UIView:0xbe0a380]>",
"<NSLayoutConstraint:0x1194bd10 V:[UIView:0xbe0a380]-(NSSpace(8))-[UIView:0xbc358e0]>",
"<NSLayoutConstraint:0x119560c0 V:[UIView:0xbc358e0(0.5)]>",
"<NSLayoutConstraint:0x1194bd60 V:[UIView:0xbc358e0]-(NSSpace(8))-[UIView:0xbcd71a0]>",
"<NSLayoutConstraint:0x119480a0 V:[UIView:0xbcd71a0]-(NSSpace(8))-[UIView:0x1194b860]>",
"<NSLayoutConstraint:0x11948fc0 V:[UIView:0x1194b860(0.5)]>",
"<NSLayoutConstraint:0x11948ff0 V:[UIView:0x1194b860]-(NSSpace(8))-[UIView:0x1193f880]>",
"<NSLayoutConstraint:0xbeca990 V:[UIView:0x1193f880]-(NSSpace(8))-[UIView:0x1194c360]>",
"<NSLayoutConstraint:0xbeca9c0 V:[UIView:0x1194c360(0.5)]>",
"<NSLayoutConstraint:0xbeca9f0 V:[UIView:0x1194c360]-(NSSpace(8))-[UIView:0x1194c1b0]>",
"<NSLayoutConstraint:0xbed69c0 V:[UIView:0x1194c1b0]-(NSSpace(8))-[UIView:0xbec8b10]>",
"<NSLayoutConstraint:0xbed69f0 V:[UIView:0xbec8b10(0.5)]>",
"<NSLayoutConstraint:0xbed6a20 V:[UIView:0xbec8b10]-(NSSpace(8))-[UIView:0xbec8960]>",
"<NSLayoutConstraint:0xbedbf50 V:[UIView:0xbec8960]-(NSSpace(8))-[UIView:0xbede4b0]>",
"<NSLayoutConstraint:0xbeda750 V:[UIView:0xbede4b0(0.5)]>",
"<NSLayoutConstraint:0xbeda5d0 V:[UIView:0xbede4b0]-(NSSpace(8))-[UIView:0xbede300]>",
"<NSLayoutConstraint:0xbc1e380 V:[UIView:0xbede300]-(NSSpace(8))-[UIView:0xbed6200]>",
"<NSLayoutConstraint:0xbc1e3b0 V:[UIView:0xbed6200(0.5)]>",
"<NSLayoutConstraint:0xbc235e0 V:[UIView:0xbed6200]-(NSSpace(8))-[UIView:0xbed8e20]>",
"<NSLayoutConstraint:0xbfbb850 V:[UIView:0xbed8e20]-(NSSpace(8))-[UIView:0xbcb56f0]>",
"<NSLayoutConstraint:0xbfbb880 V:[UIView:0xbcb56f0(0.5)]>",
"<NSLayoutConstraint:0xbfb6400 V:[UIView:0xbcb56f0]-(NSSpace(8))-[UIView:0xbc35cd0]>",
"<NSLayoutConstraint:0xbfda4f0 V:[UIView:0xbc35cd0]-(NSSpace(20))-| (Names: '|':UITableViewCellContentView:0xbcd3330 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0xbfb6400 V:[UIView:0xbcb56f0]-(NSSpace(8))-[UIView:0xbc35cd0]>
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.
源代码:
- (void)setWithLoadingState
{
[self clear];
UIActivityIndicatorView *av = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[av startAnimating];
[av setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.contentView addSubview:av];
NSDictionary *views = NSDictionaryOfVariableBindings(av);
NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:av attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
NSArray *cV =
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[av]-10-|"
options:0
metrics:nil
views:views];
[self.contentView addConstraints:[cV arrayByAddingObjectsFromArray:@[centerX]]];
[self updateConstraintsIfNeeded];
[self layoutIfNeeded];
}
- (void)setWithReviews:(NSDictionary *)reviews
{
[self clear];
UIView *topView = self.contentView;
// Create subviews with ratings.
for (NSDictionary *review in reviews[REVIEWS])
{
NSNumber *ratingViewWidth = @90;
NSNumber *ratingViewHeight = @15;
UIView *reviewContentView = [[UIView alloc] init];
UIView *reviewHeaderView = [[UIView alloc] init];
UIView *reviewInfoView = [[UIView alloc] init];
UIView *separatorView = [[UIView alloc] init];
NSString *reviewerEmail = review[REVIEWER_INFO][EMAIL];
NSDate *reviewCreatedAtDate = [NSDate dateWithString:review[CREATED_AT][DATE] format:kDateTimeFormatServer];
NSString *dateTimeFormat = [((NSString *)[I18n singleton].conventions[DATETIME]) PHPDateFormatToNSDateFormat];
NSString *reviewCreatedAt = [reviewCreatedAtDate stringValueWithFormat:dateTimeFormat];
NSNumber *reviewOverallRating = review[RATINGS][RATING];
NSString *reviewComment = review[COMMENT];
UILabel *reviewerEmailLbl = [[UILabel alloc] init];
UILabel *reviewerCreatedAtLbl = [[UILabel alloc] init];
UIView *reviewerOverallRatingView = [[UIView alloc] init];
UILabel *reviewerCommentLbl = [[UILabel alloc] init];
reviewerEmailLbl.textAlignment = NSTextAlignmentLeft;
reviewerEmailLbl.textColor = [UIColor grayColor];
reviewerEmailLbl.text = reviewerEmail;
reviewerEmailLbl.font = [UIFont systemFontOfSize:12];
reviewerCreatedAtLbl.textAlignment = NSTextAlignmentLeft;
reviewerCreatedAtLbl.textColor = [UIColor grayColor];
reviewerCreatedAtLbl.text = reviewCreatedAt;
reviewerCreatedAtLbl.font = [UIFont systemFontOfSize:12];
reviewerCommentLbl.textAlignment = NSTextAlignmentNatural;
reviewerCommentLbl.textColor = [UIColor blackColor];
reviewerCommentLbl.text = reviewComment;
reviewerCommentLbl.font = [UIFont systemFontOfSize:14];
reviewerCommentLbl.numberOfLines = 0;
UIView *starRatingView = [self getRatingViewWithFrame:CGRectMake(0, 0, ratingViewWidth.integerValue, ratingViewHeight.integerValue) rating:reviewOverallRating];
separatorView.backgroundColor = [UIColor lightGrayColor];
[reviewContentView setTranslatesAutoresizingMaskIntoConstraints:NO];
[reviewHeaderView setTranslatesAutoresizingMaskIntoConstraints:NO];
[reviewInfoView setTranslatesAutoresizingMaskIntoConstraints:NO];
[reviewerEmailLbl setTranslatesAutoresizingMaskIntoConstraints:NO];
[reviewerCreatedAtLbl setTranslatesAutoresizingMaskIntoConstraints:NO];
[reviewerOverallRatingView setTranslatesAutoresizingMaskIntoConstraints:NO];
[reviewerCommentLbl setTranslatesAutoresizingMaskIntoConstraints:NO];
[starRatingView setTranslatesAutoresizingMaskIntoConstraints:NO];
[separatorView setTranslatesAutoresizingMaskIntoConstraints:NO];
NSDictionary *views = NSDictionaryOfVariableBindings(reviewContentView, topView, reviewerEmailLbl, reviewerCreatedAtLbl, reviewerCommentLbl, reviewerOverallRatingView, starRatingView, reviewHeaderView, reviewInfoView, separatorView);
NSDictionary *metrics = NSDictionaryOfVariableBindings(ratingViewWidth, ratingViewHeight);
[reviewerOverallRatingView addSubview:starRatingView];
[reviewInfoView addSubview:reviewerEmailLbl];
[reviewInfoView addSubview:reviewerCreatedAtLbl];
[reviewHeaderView addSubview:reviewInfoView];
[reviewHeaderView addSubview:reviewerOverallRatingView];
[reviewContentView addSubview:reviewHeaderView];
[reviewContentView addSubview:reviewerCommentLbl];
[self.contentView addSubview:separatorView];
[self.contentView addSubview:reviewContentView];
NSArray *cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[starRatingView]|" options:0 metrics:nil views:views];
NSArray *cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[starRatingView]|" options:0 metrics:nil views:views];
[reviewerOverallRatingView addConstraints:[cH arrayByAddingObjectsFromArray:cV]];
cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewerEmailLbl]->=0-|" options:0 metrics:nil views:views];
[reviewInfoView addConstraints:cH];
cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewerCreatedAtLbl]->=0-|" options:0 metrics:nil views:views];
[reviewInfoView addConstraints:cH];
cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[reviewerEmailLbl]-5-[reviewerCreatedAtLbl]|" options:0 metrics:nil views:views];
[reviewInfoView addConstraints:cV];
cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewInfoView]-5-[reviewerOverallRatingView(ratingViewWidth)]|" options:0 metrics:metrics views:views];
[reviewHeaderView addConstraints:cH];
cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[reviewInfoView]->=0-|" options:0 metrics:nil views:views];
[reviewHeaderView addConstraints:cV];
cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[reviewerOverallRatingView(ratingViewHeight)]->=0-|" options:0 metrics:metrics views:views];
[reviewHeaderView addConstraints:cV];
cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[reviewHeaderView]-5-[reviewerCommentLbl]|" options:0 metrics:nil views:views];
cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewHeaderView]|" options:0 metrics:nil views:views];
[reviewContentView addConstraints:[cH arrayByAddingObjectsFromArray:cV]];
cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewerCommentLbl]|" options:0 metrics:nil views:views];
[reviewContentView addConstraints:cH];
if (topView != self.contentView)
{
NSArray *separatorConstraintH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-40-[separatorView]-40-|" options:0 metrics:nil views:views];
[self.contentView addConstraints:separatorConstraintH];
} // Adding separator horisontal constraint.
NSArray *constraintsContainerH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[reviewContentView]-|" options:0 metrics:nil views:views];
[self.contentView addConstraints:constraintsContainerH];
NSArray *constraintsContainerV;
if (topView == self.contentView)
constraintsContainerV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[reviewContentView]" options:0 metrics:nil views:views];
else
constraintsContainerV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[topView]-[separatorView(0.5@1000)]-[reviewContentView]" options:0 metrics:nil views:views];
[self.contentView addConstraints:constraintsContainerV];
topView = reviewContentView;
}
if (topView == self.contentView)
{
UILabel *errorLabel = [[UILabel alloc] init];
errorLabel.textColor = [UIColor grayColor];
errorLabel.textAlignment = NSTextAlignmentCenter;
errorLabel.text = [I18n singleton].translations[I18N_NO_REVIEWS];
errorLabel.numberOfLines = 0;
[errorLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.contentView addSubview:errorLabel];
NSDictionary *views = NSDictionaryOfVariableBindings(errorLabel);
NSArray *constraintsH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[errorLabel]-|" options:0 metrics:nil views:views];
NSArray *constraintsV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[errorLabel]-|" options:0 metrics:nil views:views];
[self.contentView addConstraints:[constraintsH arrayByAddingObjectsFromArray:constraintsV]];
}
else
{
NSDictionary *views = NSDictionaryOfVariableBindings(topView);
NSArray *constraintsV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[topView]-|" options:0 metrics:nil views:views];
[self.contentView addConstraints:constraintsV];
}
[self updateConstraintsIfNeeded];
[self layoutIfNeeded];
}
- (TQStarRatingView *)getRatingViewWithFrame:(CGRect)frame rating:(NSNumber *)rating
{
TQStarRatingView *starRatingView = [[TQStarRatingView alloc] initWithFrame:frame numberOfStar:5];
[starRatingView setScore:rating.floatValue withAnimation:NO];
starRatingView.userInteractionEnabled = NO;
starRatingView.backgroundColor = [UIColor clearColor];
return starRatingView;
}
- (void)setWithErrorMessage:(NSString *)message
{
[self clear];
UILabel *errorLabel = [[UILabel alloc] init];
errorLabel.textColor = [UIColor grayColor];
errorLabel.textAlignment = NSTextAlignmentCenter;
errorLabel.text = [I18n singleton].translations[I18N_COULD_NOT_GET_REVIEWS];
errorLabel.numberOfLines = 0;
[errorLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.contentView addSubview:errorLabel];
NSDictionary *views = NSDictionaryOfVariableBindings(errorLabel);
NSArray *constraintsH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[errorLabel]-|" options:0 metrics:nil views:views];
NSArray *constraintsV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[errorLabel]-|" options:0 metrics:nil views:views];
[self.contentView addConstraints:[constraintsH arrayByAddingObjectsFromArray:constraintsV]];
[self updateConstraintsIfNeeded];
[self layoutIfNeeded];
}
#pragma mark - Clear;
- (void)clear
{
[self.contentView removeAllSubviews];
[self updateConstraintsIfNeeded];
[self layoutIfNeeded];
}
HeightForRowAtIndexPath方法:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));
[cell setNeedsLayout];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
height += 1.0f;
return height;
}
结果:
http://i.imgur.com/bnBe4YC.png
查看层次结构:
http://i.imgur.com/Z8XQzo8.png
提前致谢并对于凌乱的代码感到抱歉(还没有重构它:))。