ios UILabel sizeToFit 不适用于自动布局 ios6

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16009405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 23:10:51  来源:igfitidea点击:

UILabel sizeToFit doesn't work with autolayout ios6

iosios6uilabelautolayout

提问by circuitlego

How am I supposed to configure programmatically (and in which method) a UILabel whose height depends on its text? I've been trying to set it up using a combination of Storyboard and code, but to no avail. Everyone recommends sizeToFitwhile setting lineBreakModeand numberOfLines. However, no matter if I put that code in viewDidLoad:, viewDidAppear:, or viewDidLayoutSubviewsI can't get it to work. Either I make the box too small for long text and it doesn't grow, or I make it too big and it doesn't shrink.

我应该如何以编程方式(以及在哪种方法中)配置高度取决于其文本的 UILabel?我一直在尝试使用 Storyboard 和代码的组合来设置它,但无济于事。每个人都建议sizeToFit在设置lineBreakModenumberOfLines. 但是,无论我是否将该代码放入viewDidLoad:, viewDidAppear:,或者viewDidLayoutSubviews我都无法使其工作。要么我把长文本的盒子弄得太小,它不会增长,要么我把它弄得太大,它不会缩小。

回答by Mark Kryzhanouski

Please notethat in most cases Matt's solutionworks as expected. But if it doesn't work for you, please, read further.

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

To make your label automatically resize height you need to do following:

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

  1. Set layout constrains for label
  2. Set height constraint with low priority. It should be lower than ContentCompressionResistancePriority
  3. Set numberOfLines = 0
  4. Set ContentHuggingPriority higher than label's height priority
  5. Set preferredMaxLayoutWidth for label. That value is used by label to calculate its height
  1. 为标签设置布局约束
  2. 设置低优先级的高度约束。它应该低于 ContentCompressionResistancePriority
  3. 设置 numberOfLines = 0
  4. 将 ContentHuggingPriority 设置为高于标签的高度优先级
  5. 为标签设置 preferredMaxLayoutWidth。标签使用该值来计算其高度

For example:

例如:

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

Using Interface Builder

使用界面生成器

  1. Set up four constraints. The height constraint is mandatory. enter image description here

  2. Then go to the label's attributes inspector and set number of lines to 0. enter image description here

  3. Go to the label's size inspector and increase vertical ContentHuggingPriority and vertical ContentCompressionResistancePriority.
    enter image description here

  4. Select and edit height constraint.
    enter image description here

  5. And decrease height constraint priority.
    enter image description here

  1. 设置四个约束。高度约束是强制性的。 在此处输入图片说明

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

  3. 转到标签的大小检查器并增加垂直 ContentHuggingPriority 和垂直 ContentCompressionResistancePriority。
    在此处输入图片说明

  4. 选择和编辑高度约束。
    在此处输入图片说明

  5. 并降低高度约束优先级。
    在此处输入图片说明

Enjoy. :)

享受。:)

回答by matt

In iOS 6, using autolayout, if a UILabel's sides (or width) and top are pinned, it will automaticallygrow and shrink vertically to fit its contents, with no code at alland no messing with its compression resistance or whatever. It is dead simple.

在 iOS 6 中,使用自动布局,如果 UILabel 的边(或宽度)和顶部被固定,它会自动垂直增长和收缩以适应其内容,根本不需要代码,也不会影响其抗压性或其他任何东西。这太简单了。

In more complex cases, just set the label's preferredMaxLayoutWidth.

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

Either way, the right thing happens automatically.

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

回答by Max MacLeod

Although the question states programmatically, having encountered the same problem, and preferring to work in Interface Builder, I thought it might be useful to add to the existing answers with an Interface Builder solution.

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

The first thing is to forget sizeToFit. Auto Layout will handle this on your behalf based upon the intrinsic content size.

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

The problem therefore is, how to get a label to fit it's content with Auto Layout? Specifically - because the question mentions it - height. Note that the same principles apply to width.

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

So let's start with an example UILabel that has a height set to 41px high:

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

enter image description here

在此处输入图片说明

As you can see in the screen grab above, "This is my text"has padding above and below. That is padding between the UILabel's height, and it's content, the text.

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

If we run the app in the simulator, sure enough, we see the same thing:

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

enter image description here

在此处输入图片说明

Now, let's select the UILabel in Interface Builder, and take a look at the default settings in the Size inspector:

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

enter image description here

在此处输入图片说明

Note the highlighted constraint above. That is the Content Hugging Priority. As Erica Sadun describes it in the excellent iOS Auto Layout Demystified, this is:

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

the way a view prefers to avoid extra padding around it's core content

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

For us, with the UILabel, the core content is the text.

对我们来说,UILabel 的核心内容就是文字。

Here we come to the heart of this basic scenario. We have given our text label two constraints. They conflict. One says "the height must be equal to 41 pixels high". The other says "hug the view to it's content so we don't have any extra padding". In our case, hug the view to it's textso we don't have any extra padding.

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

Now, with Auto Layout, with two different instructions that say do different things, the runtime has to choose one or the other. It can't do both. The UILabel can't be both 41 pixels high, andhave no padding.

现在,有了 Auto Layout,有两条不同的指令表示做不同的事情,运行时必须选择其中之一。它不能两者兼而有之。UILabel 不能既是 41 像素高,没有填充。

The way this is resolved, is by specifying priority. One instruction has to have a higher priority than the other. If both instructions say different things, and have the same priority, an exception will occur.

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

So let's give it a go. My height constraint has a priority of 1000, which is required. Content hugging height is 250, which is weak. What happens if we reduce the height constraint priority to 249?

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

enter image description here

在此处输入图片说明

Now we can see the magic start to happen. Let's try in the sim:

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

enter image description here

在此处输入图片说明

Awesome! Content hugging achieved. Only because height priority 249is less than content hugging priority 250. Basically, I'm saying "the height I specify here is less important than what I've specified for the content hugging". So, the content hugging wins.

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

Bottom line, getting the label to fit the text can be as simple as specifying the height - or width - constraint, and correct setting that priority in association with that axis' content hugging priority constraint.

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

Will leave doing the equivalent for width as an exercise for the reader!

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

回答by Nick Wood

Noticed in IOS7 sizeToFit wasn't working also - perhaps the solution may help you too

在 IOS7 中注意到 sizeToFit 也不起作用 - 也许该解决方案也可以帮助您

[textView sizeToFit];
[textView layoutIfNeeded];

回答by Monte Hurd

Another option for ensuring the label's preferredMaxLayoutWidth is kept in sync with the label's width:

确保标签的 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

回答by ArturT

I feel I should contribute as it took me a while to find the right solution:

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

  • The goal is to let Auto Layout do its work without ever calling sizeToFit(), we will do this by specifying the right constraints:
  • Specify top, bottom, and leading/trailing space constraints on your UILabel
  • Set the number of lines property to 0
  • Increment the Content Hugging Priority to 1000
  • Lower the Content Compression Resistance Priority to 500
  • On your bottom container constraint, lower the priority to 500
  • 目标是让自动布局在不调用 sizeToFit() 的情况下完成它的工作,我们将通过指定正确的约束来做到这一点:
  • 在 UILabel 上指定顶部、底部和前导/尾随空间限制
  • 将行数属性设置为 0
  • 将内容拥抱优先级增加到 1000
  • 将内容压缩阻力优先级降低到 500
  • 在底部容器约束上,将优先级降低到 500

Basically, what happens is that you tell your UILabel that even though it has a fixed height constraint, it can make break the constraint to make itself smaller in order to hug the content (if you have a single line for example), but it cannot break the constraint to make it larger.

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

回答by mixel

I added UILabelprogrammatically and in my case that was enough:

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

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

回答by sumizome

In my case I was creating a UIView subclass that contained a UILabel (of unknown length). In iOS7 the code was straightforward: set the constraints, don't worry about content hugging or compression resistance, and everything worked as expected.

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

But in iOS6 the UILabel was always clipped to a single line. None of the answers above worked for me. Content hugging and compression resistance settings were ignored. The only solution that prevented clipping was to include a preferredMaxLayoutWidth on the label. But I did not know what to set the preferred width to, as the size of its parent view was unknown (indeed, it would be defined by the contents).

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

I finally found the solution here. Because I was working on a custom view, I could just add the following method to set the preferred layout width after the constraints had been calculated once, and then recalculate them:

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

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

回答by Kazzar

i have solved with xCode6 putting "Preferred Width" to Automatic and pin the label top, leading and trailing enter image description here

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

回答by Swati

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