我在尝试使用自动布局实现一些非常基本的布局行为时遇到了麻烦。我的视图控制器在 IB 中看起来像这样:
https://i.stack.imgur.com/pg6fl.png
最上面的标签是标题标签,不知道会有多少行。我需要标题标签来显示所有文本行。我还需要将另外两个标签和小图像放在标题的正下方,不管它有多高。我已经设置了标签和小图像之间的垂直间距约束,以及标题标签与其父视图之间的顶部间距约束以及小图像与其父视图之间的底部间距约束。白色的 UIView 没有高度限制,因此它应该垂直拉伸以包含其子视图。我已将标题标签的行数设置为 0。
如何让标题标签调整大小以适应字符串所需的行数?我的理解是我不能使用 setFrame 方法,因为我使用的是自动布局。而且我必须使用自动布局,因为我需要那些其他视图保持在标题标签下方(因此有约束)。
我怎样才能做到这一点?
在 UILabel
上使用 -setPreferredMaxLayoutWidth
,其余部分应由自动布局处理。
[label setPreferredMaxLayoutWidth:200.0];
请参阅 UILabel documentation on preferredMaxLayoutWidth。
更新:
只需将storyboard中的height
约束设置为Greater than or equal to
,无需设置PreferredMaxLayoutWidth。
将标签集的行数扩展为 0,更重要的是,将自动布局集高度设置为 >= x。自动布局将完成其余的工作。您还可以包含基于先前元素的其他元素以正确定位。
https://i.stack.imgur.com/wzfxk.png
来源:http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html
多行文本的内在内容大小
UILabel 和 NSTextField 的内在内容大小对于多行文本是不明确的。文本的高度取决于行的宽度,这在解决约束时尚未确定。为了解决这个问题,这两个类都有一个名为 preferredMaxLayoutWidth 的新属性,它指定了用于计算内在内容大小的最大线宽。
由于我们通常事先不知道这个值,因此我们需要采取两步的方法来解决这个问题。首先我们让 Auto Layout 完成它的工作,然后我们在布局过程中使用生成的框架来更新首选的最大宽度并再次触发布局。
- (void)layoutSubviews
{
[super layoutSubviews];
myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
[super layoutSubviews];
}
第一次调用 [super layoutSubviews] 是标签获取其框架集所必需的,而第二次调用是在更改后更新布局所必需的。如果我们省略第二次调用,我们会得到一个 NSInternalInconsistencyException 错误,因为我们在布局过程中进行了更改,需要更新约束,但我们没有再次触发布局。
我们也可以在标签子类本身中执行此操作:
@implementation MyLabel
- (void)layoutSubviews
{
self.preferredMaxLayoutWidth = self.frame.size.width;
[super layoutSubviews];
}
@end
在这种情况下,我们不需要先调用 [super layoutSubviews],因为当 layoutSubviews 被调用时,我们已经在标签本身上有了一个框架。
为了从视图控制器级别进行此调整,我们挂钩到 viewDidLayoutSubviews。此时,第一个 Auto Layout pass 的框架已经设置好了,我们可以使用它们来设置首选的最大宽度。
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
[self.view layoutIfNeeded];
}
最后,确保标签上没有明确的高度约束,其优先级高于标签的内容压缩阻力优先级。否则它将胜过计算的内容高度。确保检查所有可能影响标签高度的约束。
我只是在与这个确切的场景作斗争,但是还有很多视图需要根据需要调整大小并向下移动。这让我发疯,但我终于想通了。
这是关键:Interface Builder 喜欢在您添加和移动视图时加入额外的约束,而您可能不会注意到。在我的例子中,我有一个视图在中途有一个额外的约束,指定它和它的父视图之间的大小,基本上将它固定到那个点。这意味着它上面的任何东西都不能调整得更大,因为它会违反这个约束。
判断是否是这种情况的一种简单方法是尝试手动调整标签大小。 IB会让你成长吗?如果是这样,下面的标签是否按照您的预期移动?在调整大小以查看约束将如何移动视图之前,请确保已检查这两项:
https://i.stack.imgur.com/ot9G6.png
如果视图被卡住,请遵循其下方的视图,并确保其中一个视图没有顶部空间来进行超级视图约束。然后只需确保标签的行数选项设置为 0,它应该会处理其余部分。
我发现您需要以下内容:
顶部约束
前导约束(例如左侧)
尾随约束(例如右侧)
设置内容拥抱优先级,水平到低,如果文本很短,它将填充给定的空间。
设置内容压缩阻力,水平到低,所以它会换行而不是尝试变宽。
将行数设置为 0。
将换行模式设置为自动换行。
在有关该主题的许多主题中找到的不同解决方案都没有完美地适用于我的案例(动态表格视图单元格中的 x 动态多行标签)。
我找到了一种方法:
在标签上设置约束并将其多行属性设置为 0 后,创建 UILabel 的子类;我叫我的 AutoLayoutLabel :
@implementation AutoLayoutLabel
- (void)layoutSubviews{
[self setNeedsUpdateConstraints];
[super layoutSubviews];
self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}
@end
我有一个 UITableViewCell ,它有一个文本换行标签。我按如下方式进行文本换行。
1) 设置 UILabel 约束如下。
https://i.stack.imgur.com/ODSQP.png
2) 设置编号。行数为 0。
3) 为 UITableViewCell 添加了 UILabel 高度约束。
@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!
4) 在 UITableViewCell 上:
priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5
一种方法...随着文本长度的增加,尝试使用更改(减小)标签文本的字体大小
Label.adjustsFontSizeToFitWidth = YES;
不定期副业成功案例分享
preferredMaxLayoutWidth
,并参阅 devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html 了解简短但内容丰富的文章,并附上动画 GIF(不是我的文章,我通过 Google 找到的)