iOS Autolayout:在resize的父视图中发布UILabels

我有一个只包含UILabel的视图。 这个标签包含多行文本。 父级具有可变宽度,可以用平移手势resize。 我的问题是,当我这样做resize的UILabel不重新计算其高度,使所有的内容仍然可见,它只是把它切断。

我已经设法修复它一点点的黑客,但它运行速度非常缓慢:

- (void)layoutSubviews { CGSize labelSize = [self.labelDescription sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)]; if (self.constraintHeight) { [self removeConstraint:self.constraintHeight]; } self.constraintHeight = [NSLayoutConstraint constraintWithItem:self.labelDescription attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:labelSize.height]; [self addConstraint:self.constraintHeight]; [super layoutSubviews]; } 

这不应该与自动布局自动发生?

编辑

我的观点的结构是:

 UIScrollView ---> UIView ---> UILabel 

这里是UIScrollView的约束:

 <NSLayoutConstraint:0x120c4860 H:|-(>=32)-[DescriptionView:0x85c81c0] (Names: '|':UIScrollView:0x85db650 )>, <NSLayoutConstraint:0x120c48a0 H:|-(32@900)-[DescriptionView:0x85c81c0] priority:900 (Names: '|':UIScrollView:0x85db650 )>, <NSLayoutConstraint:0x120c48e0 H:[DescriptionView:0x85c81c0(<=576)]>, <NSLayoutConstraint:0x120c4920 H:[DescriptionView:0x85c81c0]-(>=32)-| (Names: '|':UIScrollView:0x85db650 )>, <NSLayoutConstraint:0x120c4960 H:[DescriptionView:0x85c81c0]-(32@900)-| priority:900 (Names: '|':UIScrollView:0x85db650 )>, <NSLayoutConstraint:0x8301450 DescriptionView:0x85c81c0.centerX == UIScrollView:0x85db650.centerX>, 

这里是UIView的约束:

 <NSLayoutConstraint:0x85c4580 V:|-(0)-[UILabel:0x85bc7b0] (Names: '|':DescriptionView:0x85c81c0 )>, <NSLayoutConstraint:0x85c45c0 H:|-(0)-[UILabel:0x85bc7b0] (Names: '|':DescriptionView:0x85c81c0 )>, <NSLayoutConstraint:0x85c9f80 UILabel:0x85bc7b0.trailing == DescriptionView:0x85c81c0.trailing>, <NSLayoutConstraint:0x85c9fc0 UILabel:0x85bc7b0.centerY == DescriptionView:0x85c81c0.centerY> 

UILabel本身没有任何限制,除了将其固定在父代的边缘

好吧,我终于钉上了它。 解决方法是在viewDidLayoutSubviews设置preferredMaxLayoutWidth ,但只能第一轮布局之后。 你可以简单地通过asynchronous调度返回到主线程来安排。 所以:

 - (void)viewDidLayoutSubviews { dispatch_async(dispatch_get_main_queue(), ^{ self.theLabel.preferredMaxLayoutWidth = self.theLabel.bounds.size.width; }); } 

这样,直到标签的宽度由超级视图相关的约束条件正确设置之后 ,才能设置preferredMaxLayoutWidth

在这里工作示例项目:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch23p673selfSizingLabel4/p565p579selfSizingLabel/ViewController.m

编辑:另一种方法! 子类UILabel并重写layoutSubviews

 - (void) layoutSubviews { [super layoutSubviews]; self.preferredMaxLayoutWidth = self.bounds.size.width; } 

结果是一个自我尺寸标签 – 它自动改变其高度以适应其内容,而不pipe它的宽度如何变化(假设其宽度由约束/布局改变)。

我在解决这个问题后,提出了一个与苹果的错误。 多行文本需要双向布局方法的问题,它依赖于属性preferredMaxLayoutWidth

以下是需要添加到包含多行标签的视图控制器的相关代码:

 - (void)viewWillLayoutSubviews { // Clear the preferred max layout width in case the text of the label is a single line taking less width than what would be taken from the constraints of the left and right edges to the label's superview [self.label setPreferredMaxLayoutWidth:0.]; } - (void)viewDidLayoutSubviews { // Now that you know what the constraints gave you for the label's width, use that for the preferredMaxLayoutWidth—so you get the correct height for the layout [self.label setPreferredMaxLayoutWidth:[self.label bounds].size.width]; // And then layout again with the label's correct height. [self.view layoutSubviews]; } 

在iOS 7/8的Xcode 6.1中,我可以通过在我的视图上调用的setter方法中设置preferredMaxLayoutWidth来显示标签的文本,从而实现这个function。 我猜测它被设置为0开始。 下面的示例,其中self.teachPieceLabel是标签。 界面生成器中的标签与视图中的其他标签一起绑定。

 - (void)setTeachPieceText:(NSString *)teachPieceText { self.teachPieceLabel.text = teachPieceText; [self.teachPieceLabel setPreferredMaxLayoutWidth:[self.teachPieceLabel bounds].size.width]; }