首页 > 解决方案 > 用两列自动调整 UITableViewCell

问题描述

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

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

这是我现在所拥有的:

在此处输入图像描述

但这就是我想要实现的目标。但左列或右列都可能更高。在图片中,右列较高,但也可能是左列,具体取决于提供给它的数据。 在此处输入图像描述

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

有没有一种好方法可以让表格视图单元格能够根据更高的列垂直自动调整大小?谢谢你的帮助。


更新

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

在此处输入图像描述

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

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

更新 2

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

[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,并且我认为内容拥抱和内容压缩阻力优先级设置为我认为应该正确的值,它也会被截断。

在此处输入图像描述

以下是我的标签的定义方式:

- (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;
}

标签: iosuitableviewautolayoutnslayoutconstraint

解决方案


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

在此处输入图像描述

在这里,右边的标签更长:

在此处输入图像描述

黄色视图代表此处的表格视图单元格,其大小适合较大的标签。

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


编辑似乎有些怀疑这是否适用于实际的表格视图,所以这里有证据证明它确实有效。

在此处输入图像描述


推荐阅读