iOS:自动布局中的多行UILabel

问题描述 投票:177回答:8

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

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

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

我怎样才能做到这一点?

ios iphone cocoa-touch autolayout uilabel
8个回答
249
投票

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

[label setPreferredMaxLayoutWidth:200.0];

UILabel documentation on preferredMaxLayoutWidth

更新:

只需要在storyboard中将height约束设置为Greater than or equal to,不需要setPreferredMaxLayoutWidth。


210
投票

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


44
投票

资料来源: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。此时,第一个自动布局通道的帧已经设置,我们可以使用它们来设置首选的最大宽度。

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

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


16
投票

我只是在与这个确切的场景作斗争,但还有更多的视图需要调整大小并在必要时向下移动。这让我疯了,但我终于明白了。

这是关键:当您添加和移动视图时,Interface Builder喜欢引入额外的约束,您可能不会注意到。在我的情况下,我有一个视图中间有一个额外的约束,指定它和它的超级视图之间的大小,基本上固定到那一点。这意味着它上面没有任何东西可以调整大小,因为它会违反这个限制。

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

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


5
投票

我发现你需要以下内容:

  • 顶级约束
  • 主要约束(例如左侧)
  • 尾随约束(例如右侧)
  • 设置内容拥抱优先级,水平到低,所以如果文本很短,它将填充给定的空间。
  • 设置内容抗压力,水平到低,所以它将包裹而不是试图变宽。
  • 将行数设置为0。
  • 将换行模式设置为自动换行。

0
投票

关于该主题的许多主题中找到的不同解决方案都没有完全适合我的情况(动态表格视图单元格中的x动态多行标签)。

我找到了一种方法:

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

@implementation AutoLayoutLabel

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

@end

0
投票

我有一个UITableViewCell,它有一个文本换行标签。我的文字包装如下。

1)如下设置UILabel约束。

enter image description here

2)设置号。线条为0。

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

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4)在UITableViewCell上:

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

-9
投票

一种方法是这样做...随着文本长度的增加,尝试使用改变(减少)标签文本的fontsize

Label.adjustsFontSizeToFitWidth = YES;
© www.soinside.com 2019 - 2024. All rights reserved.