6

考虑一个包含三个UILabels 的视图,其垂直约束定义如下:

[self.view
 addConstraints:[NSLayoutConstraint
                 constraintsWithVisualFormat:@"V:[label1]-2-[label2]-2-[label3]"
                 options:0
                 metrics:nil
                 views:views]];

这将产生一个布局,其中标签垂直堆叠,每个标签之间有 2px 填充。

在我的应用程序中,有时一个或多个标签上显示的文本为 nil(或空白),这意味着标签框架的高度 == 0。在这种情况下,我希望 0 高度标签之间的 2px 填充为崩溃了。

当所有标签都有文本值时,我希望布局为:

label1 文本
[2px]
label2 文本
[2px]
label3 文本

label2文本值为 nil 时,我希望布局为:

label1 文本
[2px]
label3 文本

在后一种情况下,标签 2 实际上仍然存在,但高度为 0,并且它的 2px 填充已折叠。

问题:这可能吗?我将如何定义约束来实现这一点?

编辑

我意识到可以在子类中实现填充(边缘插入)UILabel并将填充从约束中取出。我可能会走那条路,只是希望有一种方法可以在约束定义中定义折叠此填充。

4

3 回答 3

0

是的,有一种方法可以做到这一点,您应该通过修改约束而不是弄乱UILabel子类来解决这个问题。但是,使用 VFL 就像您目前所做的那样有点棘手,因为您需要做的是保存对每个标签之间的各个约束的引用,并且 VFL 返回一个约束数组(所以您不会知道哪个是哪个)。

因此,假设您没有使用 VFL,您需要在每对标签之间单独创建约束并将其存储在 ivar 或属性中:

NSLayoutConstraint *label1To2Constraint = [NSLayoutConstraint constraintWith...];
NSLayoutConstraint *label2To3Constraint = [NSLayoutConstraint constraintWith...];

如果您没有显式添加约束以在标签上设置固定高度(您使用的 VFL 代码不这样做),那么如果标签中没有文本,它将缩小到零高度。所以现在你需要做的就是在更新标签的文本之后,检查标签是否有文本,并constant根据需要更新每对之间的约束属性:

BOOL hasLabel1Text = label1.text.length > 0;
BOOL hasLabel2Text = label2.text.length > 0;
BOOL hasLabel3Text = label3.text.length > 0;
label1To2Constraint.constant = (hasLabel1Text && hasLabel2Text) ? 2.0f : 0.0f;
label2To3Constraint.constant = (hasLabel2Text && hasLabel3Text) ? 2.0f : 0.0f;

constant可以(并且应该)在删除和重新添加约束的情况下更改现有约束。这是非常有效的。(删除和重新添加约束对内部自动布局引擎来说更加繁重,应尽可能避免。)

为了减轻您的痛苦,我想向您指出我创建的UIView+AutoLayout类别。我保证它将使用尽可能薄的第三方代码层显着改善您的自动布局体验。您将看到创建此场景所需的约束非常容易。

于 2013-10-05T06:23:17.430 回答
0

当您在标签中显示的值发生变化时,您可以重新定义约束。

如果这是一个具有三个字符串属性的视图子类,在每个属性的 setter 中,您可以调用setNeedsUpdateConstraints.

然后,在您的updateConstraints实现中,删除先前创建的约束(如果需要,您可以将其存储在属性中,因为 VFL 方法返回一个数组)并重新生成适当的约束。

如果您在处理布局的视图控制器中,则有一种类似的方法可以更新视图控制器视图上的约束:updateViewConstraints.

于 2013-10-05T07:25:23.840 回答
0

这适用于这类问题: https ://github.com/depth42/AutolayoutExtensions

于 2013-11-09T03:42:54.860 回答