无法满足约束 - 视觉格式语言

时间:2015-03-07 16:03:24

标签: ios autolayout nslayoutconstraint visual-format-language

我开始以编程方式使用自动布局和约束,但我无法理解为什么会收到以下警告

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:0x7fbbd142ead0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7fbbd162ec70(44)]>",
    "<NSLayoutConstraint:0x7fbbd1431740 V:|-(20)-[UILabel:0x7fbbd174e520'Liked']   (Names: '|':UITableViewCellContentView:0x7fbbd162ec70 )>",
    "<NSLayoutConstraint:0x7fbbd1431790 V:[UILabel:0x7fbbd174e520'Liked']-(NSSpace(8))-[UILabel:0x7fbbd174e7e0's']>",
    "<NSLayoutConstraint:0x7fbbd14317e0 V:[UILabel:0x7fbbd174e7e0's']-(20)-|   (Names: '|':UITableViewCellContentView:0x7fbbd162ec70 )>"
)

我知道导致错误的代码行是:

constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[nameLbl]-[notificationLbl]-[textLabel]-20-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:views];

但我无法理解为什么不能满足约束。这可能是一个愚蠢的问题,但我是autolayout的新手,由于文档不完整,主题令人困惑。我尝试了不同的变化和解决方案,但未能找到正确的。我错过了什么?我也粘贴了我的自定义表格视图单元格的代码,以便进行更详细的检查。

@implementation NotificationCell
@synthesize nameLbl,notificationLbl,textLabel,timeLbl,profileImgView,notificationImgView,clockImgView,didSetupConstraints;
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {


        nameLbl = [[UILabel alloc]init];
        [nameLbl setTextColor:[UIColor blueColor]];
        nameLbl.translatesAutoresizingMaskIntoConstraints = NO;
        [nameLbl setTextAlignment:NSTextAlignmentLeft];
        [nameLbl setNumberOfLines:1];

        [nameLbl setBackgroundColor:[UIColor redColor]];
        [self.contentView addSubview:nameLbl];

        notificationLbl = [[UILabel alloc]init];
        [notificationLbl setTextColor:[UIColor lightGrayColor]];
        notificationLbl.translatesAutoresizingMaskIntoConstraints = NO;
        [notificationLbl setTextAlignment:NSTextAlignmentLeft];
        [notificationLbl setNumberOfLines:1];
        [self.contentView addSubview:notificationLbl];

        textLabel = [[UILabel alloc]init];
        [textLabel setTextColor:[UIColor blueColor]];
        textLabel.translatesAutoresizingMaskIntoConstraints = NO;
        [textLabel setTextAlignment:NSTextAlignmentLeft];
        [textLabel setNumberOfLines:0];
        [textLabel setBackgroundColor:[UIColor grayColor]];
        [self.contentView addSubview:textLabel];

        timeLbl = [[UILabel alloc]init];
        [timeLbl setTextColor:[UIColor grayColor]];
        timeLbl.translatesAutoresizingMaskIntoConstraints = NO;
        [timeLbl setTextAlignment:NSTextAlignmentLeft];
        [timeLbl setNumberOfLines:1];

        [self.contentView addSubview:timeLbl];

        profileImgView = [[UIImageView alloc]init];
        [profileImgView setTranslatesAutoresizingMaskIntoConstraints:NO];
        [profileImgView setBackgroundColor:[UIColor redColor]];
        [profileImgView.layer setCornerRadius:20];
        [profileImgView.layer setMasksToBounds:YES];
        [self.contentView addSubview:profileImgView];

        clockImgView = [[UIImageView alloc]init];
        [clockImgView setTranslatesAutoresizingMaskIntoConstraints:NO];
        [clockImgView setBackgroundColor:[UIColor blueColor]];
        [clockImgView.layer setCornerRadius:10];
        [clockImgView.layer setMasksToBounds:YES];
        [self.contentView addSubview:clockImgView];

        notificationImgView = [[UIImageView alloc]init];
        [notificationImgView setTranslatesAutoresizingMaskIntoConstraints:NO];
        [notificationImgView setBackgroundColor:[UIColor purpleColor]];
        [notificationImgView.layer setCornerRadius:10];
        [notificationImgView.layer setMasksToBounds:YES];
        [self.contentView addSubview:notificationImgView];

        /*[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[_headerView(==80)]-0-[_tableView]-|"
                                                                          options:NSLayoutFormatDirectionLeadingToTrailing
                                                                          metrics:nil
                                                                            views:elementsDict]];*/



    }
    return self;
}
-(void)updateConstraints{
    if (self.didSetupConstraints == NO) {

        NSDictionary *views = NSDictionaryOfVariableBindings(nameLbl,notificationLbl,notificationImgView,textLabel,timeLbl,profileImgView,clockImgView);
        NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[profileImgView(40)]-10-[textLabel]-[clockImgView(20)]-[timeLbl(20)]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:views];
        [self.contentView addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[profileImgView]-10-[nameLbl]-[clockImgView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:views];
        [self.contentView addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[profileImgView]-10-[notificationImgView(20)]-[notificationLbl]-[clockImgView]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:views];
        [self.contentView addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[nameLbl]-[notificationLbl]-[textLabel]-20-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:views];
        [self.contentView addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[notificationImgView(20)]-[textLabel]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:views];
        [self.contentView addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-15-[profileImgView(40)]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:views];
        [self.contentView addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-15-[clockImgView(20)]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:views];
        [self.contentView addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-15-[timeLbl]" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:views];
        [self.contentView addConstraints:constraints];
        self.didSetupConstraints = YES;
    }
    [super updateConstraints];
}
- (void)layoutSubviews
{
    [super layoutSubviews];

    [self.contentView setNeedsLayout];
    [self.contentView layoutIfNeeded];

    self.textLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.textLabel.frame);
}

4 个答案:

答案 0 :(得分:1)

有几点想法:

  1. 确保您既未在表格视图中明确设置rowHeight属性,也未在tableView:heightForRowAtIndexPath:中实施UITableViewDelegate。其中任何一个都会与执行基于约束的高度计算的单元格建立冲突约束。

  2. 虽然我没有发现必要,但“Luke说”(在WWDC 2014视频What's New in Table and Collection Views中)应该为表格视图设置estimatedRowHeight(例如在viewDidLoad中)当使用约束生成行高时。

    self.tableView.estimatedRowHeight = 44;
    
  3. 我还没有发现有必要这样做,但在同一个WWDC 2014视频中,主持人Luke遇到类似于你的奇怪约束错误,直到他在他的代码中添加以下行: / p>

    self.tableView.rowHeight = UITableViewAutomaticDimension;
    

    他说在下一个种子中没有必要这样做,但在他的演示中,这是必要的。

  4. 我注意到你仍然经常会收到不可满足的约束错误(即使你已经完成了上述操作并且你的所有约束都没问题)。我发现如果你改变一个单元格的垂直约束以使优先级小于1000,它似乎可以解决这个问题(并且单元格看起来格式正确。

  5. 请注意,这种自动计算行高的行为在iOS 7中有所不同。但在iOS 8中,上述情况应该如此。如果您仍然遇到问题,请创建一个表明问题的测试项目,并将其上传到我们可以查看的位置。

答案 1 :(得分:0)

这是因为单元格的高度是44点,但是你有垂直放置的标签,其中只有空格是20 +标准间距+标准间距+ 20绝对超过44,并且仍然有标签高度,您必须考虑到:V:|-20-[nameLbl]-[notificationLbl]-[textLabel]-20-|。所以你应该增加细胞的高度。

答案 2 :(得分:0)

你需要设置 self.tableView.rowHeight = UITableViewAutomaticDimension; 它会动态制作tableViewCell高度。

您可能还需要将高度限制设置为标记大于均等,以便如果不满足,则其高度可以为0.

答案 3 :(得分:0)

根据我对动态细胞高度的经验提出的一些建议:

首先,请勿覆盖updateConstraints中的NotificationCell方法。在将所有子视图添加到init之后,在contentView方法中添加约束。

然后,更改heightForRow

的实施方式
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *) indexPath {
        NotificationCell *cell = [[NotificationCell alloc] init];

        // Do all your configuration here 
        cell.nameLabel.text = [_names objectAtIndex:indexPath.row];
        // Add all the rest too ... 

        CGFloat cellHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingSizeCompressedSize].height;
        // Add a breakpoint here to see if your constraints are right and if the height is calculated correctly

        return height + 1;
}

如果您的标签不是多线,即使没有设置文字,也应正确计算高度。但是,如果它们可以延伸多行,则需要在heightForRow方法中设置文本的值。

希望这可以解决您的问题。