UILabel sizeToFit 不支持自动布局 ios6

我应该如何通过编程方式(以及在哪种方法中)配置一个高度取决于其文本的 UILabel?我一直试图使用故事板和代码的组合来设置它,但是没有用。在设置 lineBreakModenumberOfLines时,每个人都建议使用 sizeToFit。然而,无论我把代码放在 viewDidLoad:viewDidAppear:,或 viewDidLayoutSubviews,我不能让它工作。要么我把文本框设置得太小而不能长,要么我把它设置得太大而不能缩小。

96266 次浏览

请注意,在大多数情况下,Matt 的解决方案都能正常工作,但是如果它不能正常工作,请进一步阅读。

要让你的标签自动调整高度,你需要做到以下几点:

  1. 为标签设置布局约束
  2. 设置具有低优先级的高度约束。它应该小于 ContentCompressionResitancePrition
  3. 设置 numberOfLines = 0
  4. 设置 ContentHuggingRank 高于标签的高度优先级
  5. 设置标签的首选 MaxLayoutWidth。标签使用这个值来计算它的高度

例如:

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_)]];

用 Interface Builder

  1. 设置四个约束。高度约束是强制性的。 enter image description here

  2. 然后转到标签的属性检查器,并将行数设置为0。 enter image description here

  3. 转到标签的尺寸检查器,增加垂直内容拥抱优先级和垂直内容压缩阻力优先级。
    enter image description here

  4. 选择并编辑高度约束。
    enter image description here

  5. 并降低高度约束优先级。
    enter image description here

请慢用

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));

在 iOS6中,使用自动布局,如果一个 UILabel 的边(或宽度)和顶部被固定,它将 自然而然地垂直增长和收缩以适应其内容,使用 完全没有密码并且不干扰其抗压缩性或其他。非常简单。

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

不管怎样,正确的事情会自动发生。

注意到在 IOS7 sizeToFit 也不工作-也许这个解决方案也可以帮助你

[textView sizeToFit];
[textView layoutIfNeeded];

尽管这个问题是程序化的,遇到了同样的问题,并且更喜欢在 Interface Builder 中工作,但是我认为在现有的答案中添加一个 Interface Builder 的解决方案可能会有用。

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

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

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

enter image description here

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

如果我们在模拟器中运行这个应用程序,毫无疑问,我们会看到同样的情况:

enter image description here

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

enter image description here

注意上面突出显示的约束。这是 内容拥抱优先级。正如 Erica Sadun 在优秀的 揭开 iOS 自动布局的神秘面纱中描述的那样,这是:

视图喜欢避免核心内容周围额外填充的方式

对于我们来说,使用 UILabel,核心内容就是文本。

现在我们来看看这个基本场景的核心。我们已经给了我们的文本标签两个约束。他们有冲突。一个是 “高度必须等于41像素高”。另一个是 “拥抱它的内容,所以我们没有任何额外的填充”。在我们的情况下,拥抱它的 短信视图,所以我们没有任何额外的填充。

现在,使用 Auto Layout,通过两个不同的指令执行不同的操作,运行时必须选择其中一个。不能两者兼顾。UILabel 不可能同时有41个像素高,还有没有填充。

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

那就试试吧。我的高度约束的优先级为 1000,即 需要。内容拥抱高度是 250,也就是 软弱。如果我们将高度约束优先级降低到 249会发生什么?

enter image description here

现在我们可以看到奇迹开始发生了。让我们试试模拟:

enter image description here

太棒了!内容拥抱达成。仅仅因为高度优先级 249小于内容拥抱优先级 250。基本上,我说的是 “我在这里指定的高度没有我为内容拥抱指定的高度重要”。所以,内容拥抱赢了。

底线是,使标签适合文本可以很简单,只需指定高度或宽度约束,并根据该轴的内容拥抱优先级约束正确设置优先级。

将做等效的宽度作为练习留给读者!

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

但是在 iOS6中,UILabel 总是被裁剪成一行。以上所有的答案对我都不起作用。忽略了内容拥抱和抗压缩设置。阻止剪切的唯一解决方案是在标签上包含一个首选的 MaxLayoutWidth。但是我不知道该如何设置首选宽度,因为它的父视图的大小是未知的(实际上,它将由内容来定义)。

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

- (void)layoutSubviews
{
// Autolayout hack required for iOS6
[super layoutSubviews];
self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
[super layoutSubviews];
}

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

#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

我解决了与 xCode6把“首选宽度”自动和别针的标签顶部,领先和尾随enter image description here

在我的例子中,当在 UITableViewCell 中使用标签时,标签的大小会调整,但高度会超过表单元格的高度。我就是这么做的。我根据 Max MacLeod 做了,然后确保单元格高度设置为 UITableViewAutomaticScale。

您可以在 init 或 awakeFromNib 中添加这个,

self.tableView.rowHeight = UITableViewAutomaticDimension.

在情节串连板中,选择单元格,打开 Size 检查器,并通过勾选“ Custom”复选框确保行高被设置为“ Default”。

在8.0中还有一个问题,需要在代码中设置它。

我也遇到了这个问题,因为 UIView 子类包含一个 UILabel,如果它的内部元素是一个 UILabel 的话。即使自动布局和尝试所有推荐的解决方案,标签只是不会收紧其高度的文本。对我来说,我只希望标签是一行。

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

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


}

现在在 iOS7和 iOS8上运行良好。

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

  • 我们的目标是让 Auto Layout 在不调用 sizeToFit ()的情况下完成自己的工作,我们将通过指定正确的约束来实现这一点:
  • 在 UILabel 上指定 top、 bottom 和 lead/tail 空间约束
  • 将行数属性设置为0
  • 将内容拥抱优先级提高到1000
  • 将内容压缩阻力优先级降低到500
  • 在底部容器约束上,将优先级降低到500

基本上,你告诉你的 UILabel,即使它有一个固定的高度限制,它可以打破这个限制,使自己变得更小,以拥抱内容(例如,如果你只有一行) ,但是它不能打破这个限制,使内容变大。

我通过编程方式添加了 UILabel,在我的例子中,这就足够了:

label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0

一个适合我的解决方案; 如果 UILabel 有一个固定的宽度,那么在接口文件中将约束从 constant =更改为 constant <=

enter image description here