157

我应该如何以编程方式(以及以哪种方法)配置高度取决于其文本的 UILabel?我一直在尝试使用 Storyboard 和代码的组合来设置它,但无济于事。大家sizeToFit在设置lineBreakMode和时推荐numberOfLines。但是,无论我是否将该代码放入viewDidLoad:, viewDidAppear:,或者viewDidLayoutSubviews我无法让它工作。要么我让长文本框太小,它不会增长,或者我让它太大,它不会缩小。

4

13 回答 13

410

请注意,在大多数情况下,Matt 的解决方案按预期工作。但是,如果它不适合您,请进一步阅读。

要使您的标签自动调整高度,您需要执行以下操作:

  1. 为标签设置布局约束
  2. 设置低优先级的高度约束。它应该低于 ContentCompressionResistancePriority
  3. 设置 numberOfLines = 0
  4. 将 ContentHuggingPriority 设置为高于标签的高度优先级
  5. 为标签设置 preferredMaxLayoutWidth。标签使用该值来计算其高度

例如:

self.descriptionLabel = [[UILabel alloc] init];
self.descriptionLabel.numberOfLines = 0;
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.preferredMaxLayoutWidth = 200;

[self.descriptionLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.descriptionLabel];

NSArray* constrs = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[descriptionLabel_]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)];
[self addConstraints:constrs];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[descriptionLabel_]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
[self.descriptionLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[descriptionLabel_(220@300)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];

使用界面生成器

  1. 设置四个约束。高度限制是强制性的。 在此处输入图像描述

  2. 然后转到标签的属性检查器并将行数设置为 0。 在此处输入图像描述

  3. 转到标签的尺寸检查器并增加垂直 ContentHuggingPriority 和垂直 ContentCompressionResistancePriority。
    在此处输入图像描述

  4. 选择和编辑高度约束。
    在此处输入图像描述

  5. 并降低高度约束优先级。
    在此处输入图像描述

享受。:)

于 2013-04-15T07:20:52.910 回答
66

在 iOS 6 中,使用自动布局,如果 UILabel 的边(或宽度)和顶部被固定,它将自动垂直增长和收缩以适应其内容,根本没有代码,也不会弄乱它的压缩阻力或其他任何东西。这很简单。

在更复杂的情况下,只需设置标签的preferredMaxLayoutWidth.

无论哪种方式,正确的事情都会自动发生。

于 2013-05-04T00:20:27.603 回答
42

尽管问题以编程方式说明,遇到了同样的问题,并且更喜欢在 Interface Builder 中工作,但我认为使用 Interface Builder 解决方案添加到现有答案中可能会很有用。

第一件事就是忘记sizeToFit。自动布局将根据内在内容大小代表您处理此问题。

因此,问题是,如何使用自动布局获取标签以适应其内容?具体来说 - 因为问题提到了它 - 高度。请注意,同样的原则也适用于宽度。

因此,让我们从一个高度设置为 41px 的示例 UILabel 开始:

在此处输入图像描述

正如您在上面的屏幕截图中看到的那样,"This is my text"上面和下面都有填充。那是 UILabel 的高度和它的内容,文本之间的填充。

如果我们在模拟器中运行应用程序,果然,我们看到了同样的事情:

在此处输入图像描述

现在,让我们在 Interface Builder 中选择 UILabel,并查看 Size 检查器中的默认设置:

在此处输入图像描述

请注意上面突出显示的约束。那就是内容拥抱优先级。正如 Erica Sadun 在优秀的iOS Auto Layout Demystified中描述的那样,这是:

视图倾向于避免围绕其核心内容进行额外填充的方式

对我们来说,有了 UILabel,核心内容就是文本。

在这里,我们来到了这个基本场景的核心。我们给了我们的文本标签两个约束。他们冲突。有人说“高度必须等于 41 像素高”。另一个说“拥抱它的内容,这样我们就没有任何额外的填充”。在我们的例子中,将视图拥抱它的文本,这样我们就没有任何额外的填充。

现在,使用自动布局,有两条不同的指令说做不同的事情,运行时必须选择一个或另一个。它不能两者兼得。UILabel 不能同时为 41 像素高,并且没有填充。

解决此问题的方法是指定优先级。一条指令必须具有比另一条更高的优先级。如果两条指令说的不同,并且具有相同的优先级,则会发生异常。

所以让我们试一试。我的身高限制的优先级为1000,这是必需的。内容拥抱高度是250很弱。如果我们将高度约束优先级降低到249会发生什么?

在此处输入图像描述

现在我们可以看到神奇的开始发生了。让我们在 sim 中尝试:

在此处输入图像描述

惊人的!实现内容拥抱。只是因为高度优先级249小于内容拥抱优先级250。基本上,我的意思是“我在这里指定的高度不如我为内容拥抱指定的高度重要”。所以,拥抱的内容获胜。

最重要的是,让标签适合文本可以像指定高度或宽度约束一样简单,并正确设置与该轴的内容拥抱优先级约束相关联的优先级。

将把等价的宽度作为练习留给读者!

于 2013-10-29T12:06:45.137 回答
7

在 IOS7 sizeToFit 中注意到也没有工作 - 也许解决方案也可以帮助你

[textView sizeToFit];
[textView layoutIfNeeded];
于 2013-09-25T13:52:31.360 回答
4

确保标签的 preferredMaxLayoutWidth 与标签的宽度保持同步的另一个选项:

#import "MyLabel.h"

@implementation MyLabel

-(void)setBounds:(CGRect)bounds
{
    [super setBounds:bounds];

    // This appears to be needed for iOS 6 which doesn't seem to keep
    // label preferredMaxLayoutWidth in sync with its width, which 
    // means the label won't grow vertically to encompass its text if 
    // the label's width constraint changes.
    self.preferredMaxLayoutWidth = self.bounds.size.width;
}

@end
于 2014-03-19T07:59:21.430 回答
4

我觉得我应该做出贡献,因为我花了一段时间才找到正确的解决方案:

  • 目标是让 Auto Layout 在不调用 sizeToFit() 的情况下完成其工作,我们将通过指定正确的约束来做到这一点:
  • 在 UILabel 上指定顶部、底部和前导/尾随空间约束
  • 将行数属性设置为 0
  • 将内容拥抱优先级增加到 1000
  • 将内容抗压优先级降低到 500
  • 在您的底部容器约束中,将优先级降低到 500

基本上,发生的事情是您告诉您的 UILabel 即使它具有固定的高度约束,它也可以打破约束以使自身更小以容纳内容(例如,如果您有单行),但它不能打破约束以使其更大。

于 2015-05-15T00:10:30.433 回答
3

就我而言,我正在创建一个 UIView 子类,其中包含一个 UILabel (长度未知)。在 iOS7 中,代码很简单:设置约束,不用担心内容拥抱或压缩阻力,一切都按预期工作。

但在 iOS6 中,UILabel 总是被剪裁成一行。上面的答案都不适合我。内容拥抱和压缩阻力设置被忽略。防止剪辑的唯一解决方案是在标签上包含一个 preferredMaxLayoutWidth。但是我不知道将首选宽度设置为什么,因为它的父视图的大小是未知的(实际上,它将由内容定义)。

我终于在这里找到了解决方案。因为我正在处理自定义视图,所以我可以在计算一次约束后添加以下方法来设置首选布局宽度,然后重新计算它们:

- (void)layoutSubviews
{
    // Autolayout hack required for iOS6
    [super layoutSubviews];
    self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
    [super layoutSubviews];
}
于 2013-10-31T05:18:20.633 回答
3

UILabel以编程方式添加,就我而言,这就足够了:

label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0
于 2016-03-09T19:11:55.220 回答
2

我已经解决了 xCode6 将“首选宽度”设置为自动并将标签顶部、前导和尾随固定的问题在此处输入图像描述

于 2014-10-01T09:21:18.987 回答
0

我也遇到了这个问题,UIView 子类包含一个 UILabel 作为其内部元素之一。即使使用自动布局并尝试了所有推荐的解决方案,标签也不会将其高度收紧到文本。就我而言,我只希望标签是一行。

无论如何,对我有用的是为 UILabel 添加所需的高度约束,并在调用 intrinsicContentSize 时手动将其设置为正确的高度。如果您没有 UILabel 包含在另一个 UIView 中,您可以尝试子类化 UILabel 并通过首先设置高度约束然后返回
[super instrinsicContentSize] 来提供类似的实现;而不是 [self.containerview intrinsiceContentSize];就像我在下面做的那样,它特定于我的 UIView sublass。

- (CGSize)intrinsicContentSize
{
    CGRect expectedTextBounds = [self.titleLabel textRectForBounds:self.titleLabel.bounds limitedToNumberOfLines:1];
    self.titleLabelHeightConstraint.constant = expectedTextBounds.size.height;
    return [self.containerView intrinsicContentSize];

}

现在可以在 iOS 7 和 iOS 8 上完美运行。

于 2015-02-04T12:57:00.530 回答
0
UIFont *customFont = myLabel.font;
CGSize size = [trackerStr sizeWithFont:customFont
                             constrainedToSize:myLabel.frame.size // the size here should be the maximum size you want give to the label
                                 lineBreakMode:UILineBreakModeWordWrap];
float numberOfLines = size.height / customFont.lineHeight;
myLabel.numberOfLines = numberOfLines;
myLabel.frame = CGRectMake(258, 18, 224, (numberOfLines * customFont.lineHeight));
于 2013-04-15T07:28:57.587 回答
0

对我有用的解决方案;如果您的 UILabel 具有固定宽度,请在界面文件中将约束从constant =更改为constant <=

在此处输入图像描述

于 2017-08-18T08:11:04.097 回答
-1

在我的情况下,当在 UITableViewCell 中使用标签时,标签会调整大小,但高度会超出表格单元格的高度。这对我有用。我按照 Max MacLeod 做了,然后确保单元格高度设置为 UITableViewAutomaticDimension。

您可以在您的 init 或 awakeFromNib 中添加它,

self.tableView.rowHeight = UITableViewAutomaticDimension.  

在情节提要中,选择单元格,打开大小检查器,并通过选中“自定义”复选框确保将行高设置为“默认”。

8.0 中存在一个问题,它也需要在代码中进行设置。

于 2014-11-05T20:20:34.263 回答