我应该如何以编程方式(以及以哪种方法)配置高度取决于其文本的 UILabel?我一直在尝试使用 Storyboard 和代码的组合来设置它,但无济于事。大家sizeToFit
在设置lineBreakMode
和时推荐numberOfLines
。但是,无论我是否将该代码放入viewDidLoad:
, viewDidAppear:
,或者viewDidLayoutSubviews
我无法让它工作。要么我让长文本框太小,它不会增长,或者我让它太大,它不会缩小。
13 回答
请注意,在大多数情况下,Matt 的解决方案按预期工作。但是,如果它不适合您,请进一步阅读。
要使您的标签自动调整高度,您需要执行以下操作:
- 为标签设置布局约束
- 设置低优先级的高度约束。它应该低于 ContentCompressionResistancePriority
- 设置 numberOfLines = 0
- 将 ContentHuggingPriority 设置为高于标签的高度优先级
- 为标签设置 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_)]];
使用界面生成器
设置四个约束。高度限制是强制性的。
然后转到标签的属性检查器并将行数设置为 0。
转到标签的尺寸检查器并增加垂直 ContentHuggingPriority 和垂直 ContentCompressionResistancePriority。
选择和编辑高度约束。
并降低高度约束优先级。
享受。:)
在 iOS 6 中,使用自动布局,如果 UILabel 的边(或宽度)和顶部被固定,它将自动垂直增长和收缩以适应其内容,根本没有代码,也不会弄乱它的压缩阻力或其他任何东西。这很简单。
在更复杂的情况下,只需设置标签的preferredMaxLayoutWidth
.
无论哪种方式,正确的事情都会自动发生。
尽管问题以编程方式说明,遇到了同样的问题,并且更喜欢在 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。基本上,我的意思是“我在这里指定的高度不如我为内容拥抱指定的高度重要”。所以,拥抱的内容获胜。
最重要的是,让标签适合文本可以像指定高度或宽度约束一样简单,并正确设置与该轴的内容拥抱优先级约束相关联的优先级。
将把等价的宽度作为练习留给读者!
在 IOS7 sizeToFit 中注意到也没有工作 - 也许解决方案也可以帮助你
[textView sizeToFit];
[textView layoutIfNeeded];
确保标签的 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
我觉得我应该做出贡献,因为我花了一段时间才找到正确的解决方案:
- 目标是让 Auto Layout 在不调用 sizeToFit() 的情况下完成其工作,我们将通过指定正确的约束来做到这一点:
- 在 UILabel 上指定顶部、底部和前导/尾随空间约束
- 将行数属性设置为 0
- 将内容拥抱优先级增加到 1000
- 将内容抗压优先级降低到 500
- 在您的底部容器约束中,将优先级降低到 500
基本上,发生的事情是您告诉您的 UILabel 即使它具有固定的高度约束,它也可以打破约束以使自身更小以容纳内容(例如,如果您有单行),但它不能打破约束以使其更大。
就我而言,我正在创建一个 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];
}
我UILabel
以编程方式添加,就我而言,这就足够了:
label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0
我已经解决了 xCode6 将“首选宽度”设置为自动并将标签顶部、前导和尾随固定的问题
我也遇到了这个问题,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 上完美运行。
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));
在我的情况下,当在 UITableViewCell 中使用标签时,标签会调整大小,但高度会超出表格单元格的高度。这对我有用。我按照 Max MacLeod 做了,然后确保单元格高度设置为 UITableViewAutomaticDimension。
您可以在您的 init 或 awakeFromNib 中添加它,
self.tableView.rowHeight = UITableViewAutomaticDimension.
在情节提要中,选择单元格,打开大小检查器,并通过选中“自定义”复选框确保将行高设置为“默认”。
8.0 中存在一个问题,它也需要在代码中进行设置。