可变长度标签,tableview行高和自动布局

时间:2013-08-20 18:34:48

标签: ios uitableview uilabel autolayout

关于SO和elsewhere有很多关于如何根据子视图的大小计算UITableView行的必要高度的好信息。典型的例子和我在这里应用的例子是一个包含带有可变长度文本的标签的单元格。

enter image description here

通常的建议是使用tableview sizeWithFont:constrainedToSize:lineBreakMode:中的heightForRowAtIndexPath:。但是我见过的大多数例子都是根据标签的已知宽度使用“魔术”数字。

CGSize constraint = CGSizeMake(224.0, MAXFLOAT); //224 is known to be the width available
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];

一些更好的例子可能会使用tableview的边界,然后为单元格中的其他视图减去幻数或常量,这至少会更清晰一些(如果边界在旋转等方面发生变化,效果会更好)。

CGSize constraint = CGSizeMake(self.tableview.bounds.size.width - 20 - 10 - 36 - 20, MAXFLOAT); //each non-label width subtracted
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];

这是常见的方法,但似乎缺乏。谁能说出其他单元子视图的宽度,甚至是字体,都保证不会改变(或者两个地方都会不断改变)?

我决定让单元负责提供这个高度。单元格始终知道其属性。为了实现这一点,我首先在单元格中创建了所有布局代码,引用了一些局部常量。然后我在我的自定义单元格类中添加了一个类方法,它可以根据自己的字体和大小调整常量返回任何给定文本的所需高度。

+ (CGFloat)heightRequiredForText:(NSString *)text usingWidth:(CGFloat)width
{
    //a class method that tells the caller how much height is needed for the provided text, based on the cell's size and font constants
    CGSize constraintSize = CGSizeMake(width - kMargin - kGap - kMargin - kCheckboxWidth, MAXFLOAT);
    CGRect bounds = [text boundingRectWithSize:constraintSize
                                                options:NSStringDrawingUsesLineFragmentOrigin
                                             attributes:@{NSFontAttributeName:self.labelFont}
                                                context:nil];
    return bounds.size.height;
}

这允许UITableViewController简单地提供文本和当前边界的宽度(即tableview的宽度)。字体和布局可以在单元子类中更改,一切都继续“正常工作”。

问题1

正如旁注,这是否合理?是否有更好的方法来实现同样的目标?

问题2

这是我对此(以及更标准)方法的主要问题。当单元格处于编辑模式时,标签的宽度会更改以适应编辑附件。由于行高是常量,并且标签使用自动布局,因此其高度会增加。

enter image description here

所需的行为是标签的高度保持不变,必要时应使用截断。

我在哪里以及如何实施?我应该在单元格的setEditing中做些什么吗?可能会添加另一个约束来限制高度,并启用截断,编辑时会应用相反的== NO? “滑动删除”模式怎么样 - 我认为这不会触发setEditing?那么layoutSubview - 我可以在那里做点什么吗?

1 个答案:

答案 0 :(得分:1)

我尝试了很多东西 - 我得到的最接近的是覆盖layoutSubviews,测试用户是否已切换到编辑模式,如果是这样,首先捕获标签的内在高度,然后添加临时约束来强制执行它(这是然后在退出编辑模式时删除)。除了少数边缘情况外,它运作良好。

然后我开始考虑更多的自动布局。我想要达到什么目的?当宽度减小时,我不希望标签长得更高。这是一个非常简单的约束:

[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.label
                                                                    attribute:NSLayoutAttributeHeight
                                                                    relatedBy:NSLayoutRelationLessThanOrEqual
                                                                       toItem:self.contentView
                                                                    attribute:NSLayoutAttributeHeight
                                                                   multiplier:1
                                                                     constant:0]];

添加此附加约束效果很好。请注意,我还会在编辑时将换行符模式切换为截断:

enter image description here