【问题标题】:Autosize UITableViewCell with two columns用两列自动调整 UITableViewCell
【发布时间】:2021-07-23 08:05:38
【问题描述】:

我有一个 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;
}

【问题讨论】:

    标签: ios uitableview autolayout nslayoutconstraint


    【解决方案1】:

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

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

    代表表格视图单元格的黄色视图的大小与标签中的较大者一致。

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


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

    【讨论】:

    • 感谢您的帮助。我想我已经添加了你提到的约束,但我仍然无法让表格视图单元格根据最大标签高度自动调整大小。我添加了我的约束的屏幕截图以及它在 Interface Builder 中的样子。你知道我做错了什么吗?我只是想根据两者中较大的一个来调整表格视图单元格的大小,但即使我只有一个标签并且我从标签底部到内容视图底部放置了一个约束,表格视图单元格仍然不会自动调整大小。你知道我做错了什么吗?再次感谢。
    • 抱歉附加评论,但我还添加了另一个更新,添加了我在代码中使用的约束。我只是使用 Interface Builder 对设计进行原型设计,然后在代码中实现它。我还附上了它在设备上的截图。第一项应该占用多行,但它被截断了。你看到我做错了吗?抱歉问了这么多问题。哦,顺便说一句,很棒的书。我有你的“iOS 12 编程”一书,我刚刚开始阅读它。再次感谢您的帮助。
    • 好吧,看看你的代码,你没有按照我说的去做。所以很自然你不会得到和我一样的结果。我的回答都是关于底部约束,但你的代码根本没有底部约束; “底部”这个词甚至从未出现过。
    • 我更新了它,所以高度约束被底部约束替换,我认为这解决了这个问题,但我不能确定,因为表格视图单元格永远不会增长。我认为这是一个单独的问题,所以我为此提出了一个新问题。您是否注意到我在那里做的任何错误都会阻止表格视图单元格增长并导致标签被压缩?再次感谢您的帮助和时间。我非常感激。 stackoverflow.com/questions/67337925/…
    • 我添加了一个屏幕截图来证明我在这里所说的适用于表格视图。我不明白为什么当我给你所需的信息时你会一遍又一遍地问这个问题,只要你真的做我所说的事情而不是其他事情。
    猜你喜欢
    • 2021-07-24
    • 2019-07-29
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多