iOS:自动布局中的多行 UILabel

Posted

技术标签:

【中文标题】iOS:自动布局中的多行 UILabel【英文标题】:iOS: Multi-line UILabel in Auto Layout 【发布时间】:2012-09-29 03:12:54 【问题描述】:

我在尝试使用自动布局实现一些非常基本的布局行为时遇到了麻烦。我的视图控制器在 IB 中是这样的:

最上面的标签是标题标签,不知道会有多少行。我需要标题标签来显示所有文本行。我还需要将另外两个标签和小图像放在标题的正下方,不管它有多高。我已经设置了标签和小图像之间的垂直间距约束,以及标题标签与其父视图之间的顶部间距约束以及小图像与其父视图之间的底部间距约束。白色的 UIView 没有高度限制,因此它应该垂直拉伸以包含其子视图。我已将标题标签的行数设置为 0。

如何让标题标签调整大小以适应字符串所需的行数?我的理解是我不能使用 setFrame 方法,因为我使用的是自动布局。而且我必须使用自动布局,因为我需要那些其他视图保持在标题标签下方(因此有约束)。

我怎样才能做到这一点?

【问题讨论】:

我也在与类似的问题作斗争。但我仍在努力让顶部标签动态调整其高度以适应内容。您是如何做到这一点的? 请考虑将@mwhuss 的答案标记为已接受。 你达到要求的结果了吗? 勾选此项,无需添加单行代码***.com/a/36862795/4910767 【参考方案1】:

一种方法... 随着文本长度的增加,尝试使用

更改(减小)标签文本的字体大小
Label.adjustsFontSizeToFitWidth = YES;

【讨论】:

我希望视图控制器的不同实例具有一致的外观,所以我不想更改字体大小。【参考方案2】:

我只是在与这个确切的场景作斗争,但还有很多视图需要调整大小并根据需要向下移动。这让我发疯了,但我终于想通了。

关键在于:Interface Builder 喜欢在您添加和移动视图时加入额外的约束,而您可能不会注意到。在我的例子中,我有一个视图在中途有一个额外的约束,指定它和它的父视图之间的大小,基本上将它固定到那个点。这意味着它上面的任何东西都不能调整得更大,因为它会违反这个约束。

判断是否是这种情况的一种简单方法是尝试手动调整标签大小。 IB会让你成长吗?如果是这样,下面的标签是否按照您的预期移动?在调整大小以查看约束将如何移动视图之前,请确保已检查这两项:

如果视图被卡住,请跟随其下方的视图,并确保其中一个视图没有顶部空间来进行超级视图约束。然后只需确保您的标签的行数选项设置为 0,它应该会处理其余部分。

【讨论】:

是的,在玩了很多之后,我能够得到我想要的效果。你只需要非常仔细地考虑你想要的约束。 IB 不断地施加你意想不到的限制,这于事无补。【参考方案3】:

UILabel 上使用-setPreferredMaxLayoutWidth,其余部分由自动布局处理。

[label setPreferredMaxLayoutWidth:200.0];

请参阅UILabel documentation on preferredMaxLayoutWidth。

更新:

只需要将storyboard中的height约束设置为Greater than or equal to,无需设置PreferredMaxLayoutWidth。

【讨论】:

不错,无论如何要在界面生成器中执行此操作? 同时将IB中的高度限制设置为大于或等于"。 提醒:请记得设置 numberOfLines 属性。 是的,使用任何你想要的最大宽度。 查看***.com/a/29180323/1529675 了解如何确定preferredMaxLayoutWidth 并查看devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html 了解简短但内容丰富的文章,并附有动画GIF(不是我的文章,我是通过谷歌找到的)【参考方案4】:

将您的标签集行数扩展为 0,更重要的是,将自动布局设置高度设置为 >= x。自动布局将完成其余的工作。您还可以根据前一个元素包含其他元素以正确定位。

【讨论】:

如果此方法不适合您,请参阅 Cory Imdieke 的回答,以确保后续视图不会禁止自动布局调整(可能)多行视图的大小。 这是在表格视图单元格中对我有用的唯一答案。也适用于固定数量的行(而不是 0/无限) 这不适用于我明确的首选最大宽度设置,因此请确保在使用此技术时在 IB 中将其设置为自动。干杯 设置自动最大宽度仅适用于 ios8。据我了解,它还会自动调整高度,根据我的经验,您无需设置高度约束即可使其工作。这对我使用明确的宽度有用。 这对我不起作用。我相信***.com/a/13032251/1529675 是正确答案。【参考方案5】:

来源: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];

最后,请确保您对标签没有明确的高度限制,其优先级高于标签的内容抗压缩优先级。否则它将胜过计算的内容高度。确保检查所有可能影响标签高度的约束。

【讨论】:

谢谢谢谢谢谢你不仅提供代码,更重要的是解释和示例,不仅在子类中,而且在视图控制器中。 我正在我的视图控制器中尝试这个,并且 viewDidLayoutSubviews 在 vi​​ewWillAppear 和 viewDidAppear 之后被调用。在 viewDidAppear 之后,当标签正确调整大小时会闪烁。有没有办法避免这种情况?有没有办法在用户看到任何东西之前完成调整大小?就我而言,我的多行标签位于 tableHeaderView 中,因此我还使用此示例根据标签调整标题视图的高度 (***.com/questions/20982558/…) @djibouti33 您能否提供最低限度的示例代码(例如 github repo 的格式),以便我可以轻松检查您的问题? 谢谢@Anton。我们的设计已经从 UITableView 切换到 UICollectionView,幸运的是我没有看到这种行为。如果我可以在我的 git 历史记录中创建一个小型示例项目,我会告诉你的。 自从我开始在 iOS 9 sim 上运行以来对我来说是一个问题,但是当我在 iOS 8 上进行测试时,问题就开始了。我需要手动设置最大宽度。【参考方案6】:

在有关该主题的许多主题中找到的不同解决方案都不能完美地适用于我的案例(动态表格视图单元格中的动态多行标签)。

我找到了一种方法:

在标签上设置约束并将其多行属性设置为 0 后,创建 UILabel 的子类;我叫我的 AutoLayoutLabel :

@implementation AutoLayoutLabel

- (void)layoutSubviews
    [self setNeedsUpdateConstraints];
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);


@end

【讨论】:

【参考方案7】:

我有一个带有文本环绕标签的 UITableViewCell。我的文字换行如下。

1) 如下设置 UILabel 约束。

2) 设置编号。行数为 0。

3) 为 UITableViewCell 添加了 UILabel 高度约束。

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) 在 UITableViewCell 上:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5

【讨论】:

【参考方案8】:

我发现您需要以下内容:

***约束 前导约束(例如左侧) 尾随约束(例如右侧) 设置内容拥抱优先级,水平到低,这样如果文本很短,它将填充给定的空间。 将内容压缩阻力设置为水平,将其设置为低,这样它会环绕而不是尝试变宽。 将行数设置为 0。 将换行模式设置为自动换行。

【讨论】:

这应该在 xcode9 中工作。我不必对标签高度约束做任何事情(我没有):一旦标签受到约束(尾随、前导、顶部和底部),它就可以开箱即用。 uikit 完成剩下的工作 内容拥抱优先是我的问题。感谢您让我了解该特性以及抗压性。你帮我解决了一个长达数小时的问题。

以上是关于iOS:自动布局中的多行 UILabel的主要内容,如果未能解决你的问题,请参考以下文章

如何在通知内容扩展中使用多行 UILabel / 自动布局调试布局

如何将自动布局约束添加到 tableview headerView 内的多行 UILabel?

多行 UILabel 高度,横向自动布局更高

IOS/Objective-C: MakeUILabel 使用自动布局流向多行

多行 UILabel 和 UIScrollview 使用自动布局

具有自动布局配置的 UITableCell 被截断的多行 UILabel