iOS 8 UILabel intrinsicContentSize 打破布局约束

iOS 8 UILabel intrinsicContentSize breaking layout constraints

我有一个相当简单的自定义 UITableViewCell 子类,其中包含 UISwitchUIImageViewUILabel。所有这些都是单元格 contentView 的子视图,并使用 AutoLayout 进行布局。所有子视图都以 Y 为中心,然后我创建了一系列左右边缘约束以水平排列它们。 UILabel 是最右边的项目,应该缩放以适应 UIImageView 的右边缘到它的左边和它的父视图的右边缘。当文本太长放不下时,它应该被截断。当我使用 iOS 7.1 的模拟器进行测试时,这按预期工作。但是,在 iOS 8.1 上,当标签中的文本太长而无法放入分配的 space 时,标签会将 UIImageView 推到其左侧的位置。我过去从未遇到过 UILabel 的这个问题。

编辑:我应该提到我在运行时没有遇到自动布局错误。

下面是截图和我的代码:

这是 iOS 7 上的正确行为:

这是我在 iOS 8:

上得到的

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    self.backgroundColor = [UIColor whiteColor];
    self.contentView.backgroundColor = [UIColor whiteColor];

    UISwitch *filterSwitch = [[UISwitch alloc] init];
    _filterSwitch = filterSwitch;
    filterSwitch.translatesAutoresizingMaskIntoConstraints = NO;
    [self.contentView addSubview:filterSwitch];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterSwitch
                                                                 attribute:NSLayoutAttributeCenterY
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:self.contentView
                                                                 attribute:NSLayoutAttributeCenterY
                                                                multiplier:1.0
                                                                  constant:0.0]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterSwitch
                                                                 attribute:NSLayoutAttributeLeft
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:self.contentView
                                                                 attribute:NSLayoutAttributeLeft
                                                                multiplier:1.0
                                                                  constant:10.0]];

    UIImageView *filterImageView = [[UIImageView alloc] init];
    _filterImageView = filterImageView;
    filterImageView.translatesAutoresizingMaskIntoConstraints = NO;
    filterImageView.backgroundColor = [UIColor redColor];
    filterImageView.contentMode = UIViewContentModeScaleAspectFit;
    [self.contentView addSubview:filterImageView];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterImageView
                                                                 attribute:NSLayoutAttributeCenterY
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:self.contentView
                                                                 attribute:NSLayoutAttributeCenterY
                                                                multiplier:1.0
                                                                  constant:0.0]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterImageView
                                                                 attribute:NSLayoutAttributeHeight
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:nil
                                                                 attribute:NSLayoutAttributeNotAnAttribute
                                                                multiplier:1.0
                                                                  constant:30.0]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterImageView
                                                                 attribute:NSLayoutAttributeWidth
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:filterImageView
                                                                 attribute:NSLayoutAttributeHeight
                                                                multiplier:1.0
                                                                  constant:0.0]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterImageView
                                                                 attribute:NSLayoutAttributeLeft
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:filterSwitch
                                                                 attribute:NSLayoutAttributeRight
                                                                multiplier:1.0
                                                                  constant:8.0]];

    UILabel *filterLabel = [[UILabel alloc] init];
    _filterLabel = filterLabel;
    filterLabel.translatesAutoresizingMaskIntoConstraints = NO;
    filterLabel.font = [UIFont fontWithName:@"Avenir-Medium" size:14.0];
    filterLabel.textColor = [UIColor colorWithWhite:0.25 alpha:1.0];
    filterLabel.textAlignment = NSTextAlignmentLeft;
    filterLabel.lineBreakMode = NSLineBreakByTruncatingTail;
    [self.contentView addSubview:filterLabel];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterLabel
                                                                 attribute:NSLayoutAttributeCenterY
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:self.contentView
                                                                 attribute:NSLayoutAttributeCenterY
                                                                multiplier:1.0
                                                                  constant:0.0]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterLabel
                                                                 attribute:NSLayoutAttributeLeft
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:filterImageView
                                                                 attribute:NSLayoutAttributeRight
                                                                multiplier:1.0
                                                                  constant:8.0]];
    [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterLabel
                                                                 attribute:NSLayoutAttributeRight
                                                                 relatedBy:NSLayoutRelationEqual
                                                                    toItem:self.contentView
                                                                 attribute:NSLayoutAttributeRight
                                                                multiplier:1.0
                                                                  constant:-10.0]];

    return self;
}

推测switch和label的水平抗压优先级是一样的。因此,布局不明确(不会自动检测到,所以 运行 时没有错误)。当两者都不能适应可用宽度时,将被压缩是任意的。所以,你只是在 iOS 7.

走运(或不幸,取决于你如何看待它)

将label的水平抗压能力设置得比其他两个view的水平抗压能力低,这样先压缩。

我刚试过:如果你在 IB 的视图中设置相同的情况 - H:|-[switch]-[image(==30)]-[label]-| - 并将标签的文本设置得足够长,IB 会告诉你歧义问题。