iOS 自动布局:调整父视图中 UILabels 的问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13149733/
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
iOS Autolayout: Issue with UILabels in a resizing parent view
提问by simon
I've got a view that contains only a UILabel. This label contains multiline text. The parent has a variable width that can be resized with a pan gesture. My problem is that when I do this resizing the UILabel does not recalculate its height such that all of the content is still visible, it simply cuts it off.
我有一个仅包含 UILabel 的视图。此标签包含多行文本。父级具有可变宽度,可以通过平移手势调整大小。我的问题是,当我调整 UILabel 的大小时,它不会重新计算其高度以使所有内容仍然可见,它只是将其切断。
I've managed to fix it with a bit of a hack but it is horribly slow to run:
我设法通过一些 hack 修复了它,但运行速度非常慢:
- (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];
}
Shouldn't this happen automatically with autolayout?
这不应该通过自动布局自动发生吗?
EDIT
编辑
The structure of my view is:
我的观点的结构是:
UIScrollView
---> UIView
---> UILabel
Here are the constraints on the UIScrollView:
以下是 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>,
Here are the constraints on the UIView:
以下是对 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>
The UILabel itself has no constraints on it, aside from pinning it to the edges of its parent
UILabel 本身没有任何限制,除了将其固定在其父项的边缘之外
采纳答案by simon
I've fixed this issue after raising a bug with Apple. The issue that multiline text requires a two-pass approach to layout and it all relies on the property preferredMaxLayoutWidth
我在向 Apple 提出错误后解决了这个问题。多行文本需要两遍布局的问题,这一切都依赖于属性preferredMaxLayoutWidth
Here is the relevant code that needs to be added to a view controller that contains a multiline label:
这是需要添加到包含多行标签的视图控制器的相关代码:
- (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];
}
回答by matt
Okay, I finally nailed it. The solution is to set the preferredMaxLayoutWidth
in viewDidLayoutSubviews
, but only afterthe first round of layout. You can arrange this simply by dispatching asynchronously back onto the main thread. So:
好吧,我终于搞定了。解决方法是设置preferredMaxLayoutWidth
in viewDidLayoutSubviews
,但只能在第一轮布局之后。您可以通过异步分派回主线程来简单地安排它。所以:
- (void)viewDidLayoutSubviews {
dispatch_async(dispatch_get_main_queue(), ^{
self.theLabel.preferredMaxLayoutWidth = self.theLabel.bounds.size.width;
});
}
That way, you don't set preferredMaxLayoutWidth
until afterthe label's width has been properly set by its superview-related constraints.
这样,preferredMaxLayoutWidth
直到标签的宽度由其与超视图相关的约束正确设置后,您才进行设置。
Working example project here:
这里的工作示例项目:
EDIT:Another approach! Subclass UILabel and override layoutSubviews
:
编辑:另一种方法!子类 UILabel 和覆盖layoutSubviews
:
- (void) layoutSubviews {
[super layoutSubviews];
self.preferredMaxLayoutWidth = self.bounds.size.width;
}
The result is a self-sizing label - it automatically changes its height to accommodate its contents no matter how its width changes (assuming its width is changed by constraints / layout).
结果是一个自动调整大小的标签 - 无论其宽度如何变化(假设其宽度因约束/布局而改变),它都会自动改变其高度以适应其内容。
回答by Evan R
In Xcode 6.1 for iOS 7/8, I was able to get this to work by just setting preferredMaxLayoutWidth
in a setter method that's called on my view to display the text for the label. I'm guessing it was set to 0
to begin with. Example below, where self.teachPieceLabel
is the label. The label is wired up with constraints alongside other labels in a view in Interface Builder.
在适用于 iOS 7/8 的 Xcode 6.1 中,我只需preferredMaxLayoutWidth
在我的视图中调用的 setter 方法中设置以显示标签文本,就可以使其工作。我猜它已经0
开始了。下面的例子,self.teachPieceLabel
标签在哪里。该标签与 Interface Builder 中视图中的其他标签一起使用约束。
- (void)setTeachPieceText:(NSString *)teachPieceText {
self.teachPieceLabel.text = teachPieceText;
[self.teachPieceLabel setPreferredMaxLayoutWidth:[self.teachPieceLabel bounds].size.width];
}