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。
选择并编辑高度约束。
减小高度约束优先级。
愉快使用! :)
preferredMaxLayoutWidth
或固定标签的宽度(或其左右两侧),就这些!然后它会根据内容自动垂直伸缩以适应内容。 - matt在 iOS 6 中,使用自动布局(autolayout)时,如果将一个 UILabel 的两侧(或宽度)和顶部固定,它将会根据其内容自动垂直增长和收缩,而无需编写任何代码或者干扰它的压缩阻力等设置。这非常简单。
在更复杂的情况下,只需要设置标签的preferredMaxLayoutWidth
属性。
无论哪种方式,正确的事情都会自动发生。
虽然问题中提到了程序化,但我也曾遇到过同样的问题,并且更喜欢使用Interface Builder工具。因此,我认为通过Interface Builder解决此问题可能会对现有答案有所帮助。
首先,要忘记sizeToFit
方法。Auto Layout会根据内在内容大小自动处理此问题。
因此,问题是如何使用Auto Layout使标签适应其内容呢?具体来说-因为问题提到了-高度。请注意,相同的原则适用于宽度。
因此,让我们从一个高度设置为41像素的示例UILabel开始:
正如您在上面的屏幕截图中看到的那样,"This is my text"
上下有填充。即是在UILabel高度和文本之间的填充。
如果在模拟器中运行此应用程序,则可以看到相同的结果:
现在,让我们在Interface Builder中选择UILabel,并查看“大小”检查器中的默认设置:
请注意上面突出显示的约束。这是内容挤压优先级。正如Erica Sadun在她出色的iOS Auto Layout Demystified中所描述的那样,它是:
视图希望避免其核心内容周围的额外填充方式
对于我们来说,对于UILabel,核心内容就是文本。
这里是基本情景的核心。我们为文本标签设置了两个约束条件,它们相互冲突。一个说 "高度必须等于 41 像素高"。另一个说 "贴近视图到其内容,使得我们没有任何多余的填充"。在我们的情况下,贴近视图到其文本,所以我们没有任何额外的填充。
现在,使用自动布局,有两个不同的指令要求做不同的事情,运行时必须选择其中一个。它不能同时完成两个指令。UILabel 既不能是 41 像素高,也不能没有填充。
解决方法是指定优先级。必须有一个指令比另一个指令具有更高的优先级。如果两个指令说不同的事情,并且具有相同的优先级,则会出现异常。
那么让我们试一试。我的高度约束具有1000的优先级,这是必需的。内容贴近高度为250,这是弱的。如果将高度约束优先级降低到249会发生什么?
现在我们可以看到魔法开始发生了。让我们在模拟器中试一下:
太棒了!内容贴近达成。只因为高度优先级249小于内容贴近优先级250。基本上,我是在说"我在这里指定的高度不如我为内容贴近指定的重要"。因此,内容贴近获胜。
底线是,使标签适合文本可能就像指定高度或宽度约束一样简单,并正确设置与该轴的内容贴近优先级约束相关联的优先级。
将宽度等效执行留给读者作为练习!
[textView sizeToFit];
[textView layoutIfNeeded];
setNeedsUpdateConstraints
时,请添加 layoutIfNeeded
。但情况可能略有不同。 - Gon确保标签的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
我通过编程方式添加了一个UILabel
,在我的情况下这已经足够了:
label.translatesAutoresizingMaskIntoConstraints = false
label.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
label.numberOfLines = 0
- (void)layoutSubviews
{
// Autolayout hack required for iOS6
[super layoutSubviews];
self.bodyLabel.preferredMaxLayoutWidth = self.bodyLabel.frame.size.width;
[super layoutSubviews];
}
- (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上完美运行。
intrinsicContentSize
。运行时应该能够根据您正确设置的约束来计算此内容。 - John Rogers
label.sizeToFit()
,约束已经足够了。在Playground中没有创建标签。到目前为止,我发现在Playground中使其工作的唯一方法是执行label.sizeToFit()
。 - mfaani