使用两列自动调整 UITableViewCell

Autosize UITableViewCell with two columns

我有一个包含两列的 UITableViewCell。每列都是一个 UILabel,每个标签都是多行的 (numberOfLines = 0)。

我想要的是 table 视图单元格根据较高的标签垂直调整大小。我为每个标签的左右和顶部设置了约束,但我不确定如何添加底部约束,因为它需要是对最高标签的约束。

这是我现在拥有的:

但这就是我想要实现的目标。但是左列或右列都可以更高。在图片中,右列更高,但根据提供给它的数据,它也可能是左列。

我想过添加一个高度约束来将两个标签约束到相同的高度,然后从那里添加底部约束,但是较短的标签将不会垂直对齐,或者我不知道有什么办法在不子类化 UILabel 或使用 UITextView 的情况下垂直对齐它们,如果可能的话我宁愿不这样做。

有什么好方法可以让 table 视图单元格能够根据哪一列更高来垂直自动调整大小?感谢您的帮助。


更新

我根据提供的答案添加了两个额外的约束。但出于某种原因,我仍然无法让它自动调整 table 单元格的大小。我在 Interface Builder 中将行高设置为自动。这是我目前配置的约束。

约束中是否有任何内容会阻止 table 视图单元格的高度增加以匹配标签的高度?

我不确定这是否是问题所在,但我也尝试按照建议向内容视图添加低优先级高度约束,但我无法添加约束或者我不知道怎么做。我可以将高度约束添加到其他视图,但不能添加到 table 视图单元格的内容视图。

更新 2

这里是代码中的约束。这是在 UITableViewCell 子类中,此代码 运行s 作为单元格初始化的一部分。

[self addSubview:self.firstLabel];
[self addSubview:self.secondLabel];

NSLayoutConstraint *heightConstraint = [self.heightAnchor constraintEqualToConstant:1.0f];
[heightConstraint setPriority:50];

[NSLayoutConstraint activateConstraints:@[
    [self.firstLabel.leadingAnchor constraintEqualToAnchor:self.contentView.layoutMarginsGuide.leadingAnchor],
    [self.firstLabel.topAnchor constraintEqualToAnchor:self.contentView.layoutMarginsGuide.topAnchor constant:0.0f],
    [self.firstLabel.trailingAnchor constraintEqualToAnchor:self.centerXAnchor constant:-4.0f],
    
    [self.secondLabel.leadingAnchor constraintEqualToAnchor:self.centerXAnchor constant:4.0f],
    [self.secondLabel.firstBaselineAnchor constraintEqualToAnchor:self.firstLabel.firstBaselineAnchor],
    [self.secondLabel.trailingAnchor constraintEqualToAnchor:self.contentView.layoutMarginsGuide.trailingAnchor],
    
    [self.contentView.heightAnchor constraintGreaterThanOrEqualToAnchor:self.firstLabel.heightAnchor constant:8.0f],
    [self.contentView.heightAnchor constraintGreaterThanOrEqualToAnchor:self.secondLabel.heightAnchor constant:8.0f],
    
    heightConstraint
]];

这是在设备上 运行 时的样子。标签都很短,除了第一个,它应该跨越几行。但出于某种原因,即使我将行数设置为 0 并且我认为内容拥抱和内容压缩阻力优先级设置为我认为应该正确的设置,它仍被 t运行 处理。

我的标签是这样定义的:

- (UILabel *)firstLabel {
    if (!self->_firstLabel) {
        self->_firstLabel = [[UILabel alloc] init];
        self->_firstLabel.translatesAutoresizingMaskIntoConstraints = NO;
        self->_firstLabel.numberOfLines = 0;
        self->_firstLabel.userInteractionEnabled = NO;
        self->_firstLabel.contentMode = UIViewContentModeScaleToFill;
        [self->_firstLabel setContentHuggingPriority:251 forAxis:UILayoutConstraintAxisHorizontal];
        [self->_firstLabel setContentHuggingPriority:251 forAxis:UILayoutConstraintAxisVertical];
        [self->_firstLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
        [self->_firstLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
        self->_firstLabel.textAlignment = NSTextAlignmentNatural;
        self->_firstLabel.lineBreakMode = NSLineBreakByTruncatingTail;
        self->_firstLabel.baselineAdjustment = UIBaselineAdjustmentAlignBaselines;
        self->_firstLabel.adjustsFontSizeToFitWidth = NO;
        
        //TODO: remove this
        self->_firstLabel.backgroundColor = [UIColor orangeColor];
    }
    return self->_firstLabel;
}

- (UILabel *)secondLabel {
    if (!self->_secondLabel) {
        self->_secondLabel = [[UILabel alloc] init];
        self->_secondLabel.translatesAutoresizingMaskIntoConstraints = NO;
        self->_secondLabel.numberOfLines = 0;
        self->_secondLabel.userInteractionEnabled = NO;
        self->_secondLabel.contentMode = UIViewContentModeScaleToFill;
        [self->_secondLabel setContentHuggingPriority:251 forAxis:UILayoutConstraintAxisHorizontal];
        [self->_secondLabel setContentHuggingPriority:251 forAxis:UILayoutConstraintAxisVertical];
        [self->_secondLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
        [self->_secondLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
        self->_secondLabel.textAlignment = NSTextAlignmentNatural;
        self->_secondLabel.lineBreakMode = NSLineBreakByTruncatingTail;
        self->_secondLabel.baselineAdjustment = UIBaselineAdjustmentAlignBaselines;
        self->_secondLabel.adjustsFontSizeToFitWidth = NO;
        
        //TODO: remove this
        self->_secondLabel.backgroundColor = [UIColor yellowColor];
    }
    return self->_secondLabel;
}

是的,当您了解约束不等式和优先级时,这就非常简单了。这里左边的标签比较长:

这里右边的标签比较长:

此处代表 table 视图单元格的黄色视图的大小适合标签中较大的一个。

这是怎么做到的?除了以正常方式将标签固定在顶部、左侧和右侧之外,超级视图(黄色视图)底部还有两个大于或等于约束,一个到每个标签的底部;并且它本身以非常低的优先级被赋予非常小的高度(作为一种告诉布局引擎使高度尽可能小同时仍然遵守不等式的方式,否则这将是模棱两可的)。


EDIT 这似乎对实际 table 视图是否有效存在一些疑问,因此这里证明它确实有效。