以编程方式更改 UILabel 上的约束会破坏布局

Programmatically change constraint on a UILabel breaks layout

我有一个带有两个约束的 UILabel。我激活了一个约束,另一个我禁用了。我有一个禁用第一个约束并激活第二个约束的按钮。然后,当第二次点击时,禁用第二个约束并重新激活第一个约束。第一次点击此按钮会按预期工作。 UILabel 包括所有其他约束到它的 UILabel,移动到不同的位置。但是,当点击按钮将其移回时,布局会中断。 UILabel 移动到一个几乎与它之前所在位置相同的位置,但所有其他约束到它的 UILabel 都留在原处,不会移回其原始位置。

这是处理激活约束的函数。

- (void)tapOnce:(UIGestureRecognizer *)gesture
{
    if (_constraintLabelOne.isActive) {
        [_constraintLabelOne setActive:NO];
        [_constraintLabelTwo setActive:YES];
    } else {
        [_constraintLabelTwo setActive:NO];
        [_constraintLabelOne setActive:YES];
    }
    [self layoutIfNeeded];
}

约束看起来像这样。

_constraintLabelOne = [NSLayoutConstraint constraintWithItem:myLabel
                                                                   attribute:NSLayoutAttributeTop
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:topView
                                                                   attribute:NSLayoutAttributeBottom
                                                                  multiplier:1.0
                                                                    constant:6];
_constraintLabelTwo = [NSLayoutConstraint constraintWithItem:myLabel
                                                                   attribute:NSLayoutAttributeTop
                                                                   relatedBy:NSLayoutRelationEqual
                                                                      toItem:topView
                                                                   attribute:NSLayoutAttributeBottom
                                                                  multiplier:1.0
                                                                    constant:20];

约束到 myLabel 的其他标签在第一次调用 tapOnce 后卡在第二个位置。 myLabel 约束更新后,为什么它们不回到初始位置?

我附上了一张屏幕截图,其中包含当前行为的绘图。蓝色方框代表topView。洋红色框代表 myLabel。第一个屏幕是在调用 tapOnce 之前。中间的屏幕是在调用 tapOnce 一次之后。右边的屏幕是在调用 tapOnce 两次之后。

我这样做的方法是将其中一个约束的 priority 设置得较低,因此它是 "optional",例如UILayoutPriorityDefaultHigh,甚至更高,例如999.

然后您可以同时激活两个约束,所需的约束将优先。

要设置它,请为默认状态设置所需的约束,并为按钮按下状态设置可选约束。

您可以从两个约束都处于活动状态开始,然后在按下按钮时,您只需禁用(设置 constraint.active = NO)所需的约束,另一个将优先。再次按下按钮时,您只需 re-enable 所需的约束。

我明白了。发生的事情是 UILabel 的高度不受约束,因此当第二个约束被停用并且第一个约束重新激活时,高度自动增加(见下图)。为了解决这个问题,我必须手动限制所有视图项的高度。如果有人有更好的解决方案,请 post 因为我不想手动设置每个项目的高度,因为这可能会导致布局在不同设备上中断。

更新

感谢 siburb 为 UI 元素指出 Content Hugging Priority 属性。我的问题的根源是未设置此 属性,这允许我的 UI 标签的高度扩展。解决方案是将此 属性 设置为 750 或更高的值。

[myLabel setContentHuggingPriority:750 forAxis:UILayoutConstraintAxisVertical];