iOS 8 UILabel intrinsicContentSize 打破布局约束
iOS 8 UILabel intrinsicContentSize breaking layout constraints
我有一个相当简单的自定义 UITableViewCell
子类,其中包含 UISwitch
、UIImageView
和 UILabel
。所有这些都是单元格 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 会告诉你歧义问题。
我有一个相当简单的自定义 UITableViewCell
子类,其中包含 UISwitch
、UIImageView
和 UILabel
。所有这些都是单元格 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 会告诉你歧义问题。