自动布局中的多行 UILabel

我有麻烦,试图实现一些非常基本的布局行为与自动布局。我的视图控制器在 IB 中是这样的:

enter image description here

顶部的标签是标题标签,我不知道它会有多少行。我需要标题标签来显示所有的文本行。我还需要其他两个标签和小的形象被布置在正下方的标题,无论它碰巧是高。我已经设置了标签和小图像之间的垂直间距约束,以及标题标签和其超视图之间的顶部间距约束和小图像和其超视图之间的底部间距约束。白色 UIView 没有高度限制,因此它应该垂直拉伸以包含其子视图。我已经将 title 标签的行数设置为0。

如何使标题标签调整大小以适应字符串所需的行数?我的理解是,我不能使用 setFrame 方法,因为我正在使用 Auto Layout。我必须使用自动布局,因为我需要那些其他视图保持在标题标签之下(因此受到约束)。

我该怎么做?

127833 次浏览

有一个办法。 当文本长度增加时,尝试使用

Label.adjustsFontSizeToFitWidth = YES;

我只是在与这个确切的场景作斗争,但有相当多的视图需要调整大小,并在必要时向下移动。这快把我逼疯了,但我终于想明白了。

关键在于,当你添加和移动视图时,Interface Builder 喜欢添加额外的约束,而你可能没有注意到。在我的例子中,我有一个向下的视图,它有一个额外的约束,指定它和它的超视图之间的大小,基本上把它固定在那个点上。这意味着,在它之上的任何东西都不能调整大小,因为它将违反这一约束。

一个简单的方法来判断是否是这种情况是通过尝试手动调整标签的大小。IB 允许你种吗?如果是这样,下面的标签是否如您所期望的那样移动?在调整视图大小以查看约束将如何移动视图之前,请确保同时检查这两个属性:

IB Menu

如果视图卡住了,请跟随视图下面的视图,并确保其中一个视图没有顶部空间来进行监视约束。然后只要确保标签的行数选项被设置为0,它就会处理剩下的部分。

UILabel上使用 -setPreferredMaxLayoutWidth,其余的自动布局应该处理。

[label setPreferredMaxLayoutWidth:200.0];

看看 UILabel 文档关于 preredMaxLayoutWidth

更新:

只需要将故事板中的 height约束设置为 Greater than or equal to,不需要设置 PreferredMaxLayoutWidth。

将您的标签设置行数展开为0,更重要的是,自动布局设置高度为 > = x。自动布局将完成其余的工作。您还可以根据前面的元素包含其他元素,以便正确定位。

auto layout

资料来源: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

多行文本的内在内容大小

对于多行文本,UILabel 和 NSTextField 的内部内容大小是不明确的。文本的高度取决于行的宽度,这在解决约束时尚未确定。为了解决这个问题,这两个类都有一个新的属性叫做 preredMaxLayoutWidth,它指定了计算内部内容大小的最大行宽。

因为我们通常不会提前知道这个值,所以我们需要采取两步的方法来获得正确的结果。首先,我们让自动布局完成它的工作,然后我们在布局传递中使用结果帧来更新首选的最大宽度和触发器布局。

- (void)layoutSubviews
{
[super layoutSubviews];
myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
[super layoutSubviews];
}

对[ super layoutSubviews ]的第一个调用对于标签获得它的帧集是必需的,而第二个调用对于更改后更新布局是必需的。如果我们省略第二个调用,我们会得到一个 NSInternalIncontencyException 错误,因为我们已经在布局传递中做了需要更新约束的更改,但是我们没有再次触发布局。

我们也可以在 label 子类本身中这样做:

@implementation MyLabel
- (void)layoutSubviews
{
self.preferredMaxLayoutWidth = self.frame.size.width;
[super layoutSubviews];
}
@end

在这种情况下,我们不需要首先调用[ super layoutSubviews ] ,因为当 layoutSubviews 被调用时,我们已经在标签本身上有了一个框架。

为了从视图控制器级别进行此调整,我们连接到 viewDidLayoutSubviews。此时,第一个自动布局传递的帧已经设置好了,我们可以使用它们来设置首选的最大宽度。

- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
[self.view layoutIfNeeded];
}

最后,确保标签上没有显式的高度约束,该约束的优先级高于标签的内容压缩阻力优先级。否则它将超过内容的计算高度。确保检查所有可能影响标签高度的约束条件。

在关于这个主题的许多主题中找到的不同解决方案,没有一个对我的案例是完美的(x 动态表视图单元格中的动态多行标签)。

我找到了一个办法:

在设置了标签上的约束并将其多行属性设置为0之后,创建 UILabel 的子类; 我将我的类命名为 AutoLayoutLabel:

@implementation AutoLayoutLabel


- (void)layoutSubviews{
[self setNeedsUpdateConstraints];
[super layoutSubviews];
self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}


@end

我有一个 UITableViewCell,它有一个文本换行标签。

1)设置 UILabel 约束如下。

enter image description here

2)将行数设置为0。

3)添加 UILabel 高度约束到 UITableViewCell。

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) UITableViewCell:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5

我发现你需要以下几点:

  • 最高限制
  • 主要约束(如左侧)
  • 尾随约束(如右侧)
  • 设置内容拥抱优先级,从水平到低,这样,如果文本较短,它将填充给定的空间。
  • 设置内容压缩阻力,水平到低,所以它将包装,而不是尝试变得更宽。
  • 将行数设置为0。
  • 将换行模式设置为换行。