iOS:自动版式中的多行UILabel


183

我在尝试通过自动版式实现一些非常基本的版式行为时遇到了麻烦。我的视图控制器在IB中如下所示:

在此处输入图片说明

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

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

我怎样才能做到这一点?


3
我也在努力解决类似的问题。但是,我仍然在努力获得顶部标签来动态调整其高度以适合内容。您是如何实现的?
jbandi

1
请考虑将@mwhuss的答案标记为已接受。
jemmons,2014年

1
您是否达到了要求的结果?
Aniruddha 2014年

选中此复选框,您无需添加任何代码行stackoverflow.com/a/36862795/4910767
Badal Shah 2016年

Answers:


254

使用-setPreferredMaxLayoutWidthUILabel和自动版式应该处理其余部分。

[label setPreferredMaxLayoutWidth:200.0];

请参见preferredMaxLayoutWidth上UILabel文档

更新:

只需将height情节Greater than or equal to提要中的约束设置为,无需设置setPreferredMaxLayoutWidth。


8
不错,无论如何在界面生成器中做到这一点?
Sjoerd Perfors

12
还设置IB高度限制为大于或等于”
jowie

10
提醒:请记住设置numberOfLines属性。
李富民

2
是的,使用任何您想要的最大宽度。
mwhuss'3

4
有关如何确定的信息,请参见stackoverflow.com/a/29180323/1529675,有关简短但内容丰富的文章preferredMaxLayoutWidth,请参见devetc.org/code/2014/07/auto-layout-and-views-that-wrap.html,并附带动画GIF(不是我的文章,而是通过Google找到的)
tboyce12

213

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

自动布局


如果此方法对您不起作用,请参阅Cory Imdieke的答案,以确保后续视图不会阻止自动版式调整(可能)多行视图的大小。
汤姆·霍华德

1
这是在Table View Cell中对我有用的唯一答案。也可用于固定数量的行(而不是0 /无限制)
bgolson 2014年

使用明确的首选最大宽度设置对我来说不起作用,因此请确保在使用此技术时将其设置为IB中的自动设置。干杯
jmc 2015年

设置自动最大宽度仅在iOS8中可用。根据我的理解,它也会自动调整高度,根据我的经验,您无需设置高度限制即可工作。这对我来说使用显式宽度有效。
托尼

1
这对我不起作用。我相信stackoverflow.com/a/13032251/1529675是正确的答案。
tboyce12

48

资料来源:http : //www.objc.io/issue-3/advanced-auto-layout-toolbox.html

多行文字的内在内容大小

对于多行文本,UILabel和NSTextField的固有内容大小不明确。文本的高度取决于线条的宽度,在解决约束时尚待确定。为了解决此问题,两个类都具有一个名为preferredMaxLayoutWidth的新属性,该属性指定用于计算内部内容大小的最大行宽。

由于我们通常不预先知道此值,因此我们需要采取两步方法来实现此目的。首先,我们让自动版式完成其工作,然后使用版式传递中的结果帧更新首选的最大宽度并再次触发版式。

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

第一次调用[super layoutSubviews]是标签获得其框架集所必需的,而第二次调用是在更改后更新布局所必需的。如果省略第二个调用,则会收到NSInternalInconsistencyExceptionException错误,因为我们在布局传递中进行了更改,需要更新约束,但没有再次触发布局。

我们还可以在标签子类本身中执行此操作:

@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];
}

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


谢谢谢谢谢谢您不仅提供了代码,而且更重要的是,不仅在子类中而且从视图控制器执行此操作的说明和示例。
djibouti33

我正在我的视图控制器中尝试此操作,并且在viewWillAppear和viewDidAppear之后调用了viewDidLayoutSubviews。在viewDidAppear之后,标签正确调整大小时会闪烁。有什么办法可以避免这种情况?有没有办法在用户看到任何东西之前完成大小调整?在我的情况下,我的多行标签位于tableHeaderView中,因此我还将使用此示例(stackoverflow.com/questions/20982558/…)根据标签调整标题视图的高度
djibouti33

@ djibouti33您能否提供最少的示例代码(例如github repo格式),以便我可以轻松地检查您的问题?
安东·马托索夫

谢谢@安东。此后,我们的设计已从UITableView切换到UICollectionView,所幸我没有看到此行为。如果我可以了解自己的git历史来创建一个小型示例项目,那么我会告诉你。
djibouti33

自从我开始在iOS 9 sim上运行以来,对我来说是一个问题,但是当我在iOS 8上进行测试时,麻烦就开始了。我需要手动设置最大宽度。
naz 2015年

17

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

这是关键:在添加和移动视图时,Interface Builder喜欢添加额外的约束,您可能不会注意到。在我的情况下,我有一个视图,位于视图的一半下方,该视图有一个额外的约束条件,用于指定视图与其父视图之间的大小,基本上将其固定在该点上。这意味着它上面的任何内容都无法调整得更大,因为它会违反该限制。

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

IB菜单

如果视图被卡住,请遵循其下的视图,并确保其中一个视图没有顶部空间来约束视图。然后,只需确保将标签的行数选项设置为0,其余的就应该由它来处理。


是的,经过大量的尝试,我能够获得想要的效果。您只需要非常仔细地考虑所需的约束。IB不断施加您意想不到的约束并没有帮助。
James Harpe 2012年

5

我发现您需要以下物品:

  • 首要约束
  • 前导约束(例如左侧)
  • 尾随约束(例如右侧)
  • 设置内容优先级,将水平设置为低,因此如果文本较短,它将填充给定的空间。
  • 将内容压缩阻力(水平方向)设置为低,以便将其包裹而不是尝试变宽。
  • 将行数设置为0。
  • 将换行模式设置为自动换行。

这应该在xcode9中工作。我不必对标签高度限制做任何事情(我没有):标签一旦受到约束(拖尾,前导,顶部和底部),它就可以立即使用。uikit完成了其余工作
Anton Tropashko

内容优先是我的问题。感谢您让我知道该属性以及抗压缩性。您帮助我解决了一个小时的问题。
David Gay

0

在该主题的许多主题中找到的所有不同解决方案中,没有一种适合我的情况(在动态表格视图单元格中有x个动态多行标签)。

我找到了一种方法:

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

@implementation AutoLayoutLabel

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

@end

0

我有一个带有文本换行标签的UITableViewCell。我按如下方式处理文本换行。

1)如下设置UILabel约束。

在此处输入图片说明

2)设置编号 行到0。

3)向UITableViewCell添加了UILabel高度限制。

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4)在UITableViewCell上:

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

-12

一种方法...随着文本长度的增加,尝试使用以下方法更改(减小)标签文本的字体大小

Label.adjustsFontSizeToFitWidth = YES;

1
我希望视图控制器的不同实例具有一致的外观,所以我不想更改字体大小。
詹姆斯·哈普 James Harpe)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.