以编程方式更改 UILabel 上的约束打破布局
Posted
技术标签:
【中文标题】以编程方式更改 UILabel 上的约束打破布局【英文标题】:Programmatically change constraint on a UILabel breaks layout 【发布时间】:2019-06-24 22:40:28 【问题描述】:我有一个带有两个约束的 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];
在第一次调用tapOnce
后,限制为myLabel
的其他标签卡在第二个位置。 myLabel
约束更新后,它们为什么不回到初始位置?
我附上了一张带有当前行为图的屏幕截图。蓝色框代表topView
。洋红色框代表myLabel
。第一个屏幕是在调用tapOnce
之前。中间的屏幕是在拨打tapOnce
一次之后。右侧画面是调用tapOnce
两次之后。
【问题讨论】:
期望的行为是什么? 第二次调用tapOnce
后,所需的行为是屏幕看起来像最左边的样子。布局不应看起来像最右边的屏幕。
抱歉,我以为最左边的屏幕是起点。您说“第一个屏幕是在调用 tapOnce 之前”。如果不是,您第一次拨打tapOnce
之前的屏幕是什么样的?您能否展示tapOnce
的效果应该是什么,即之前和之后?或者你是说一次点击会使我们从第一个屏幕转到第二个屏幕,而第二次点击应该使我们从第二个屏幕回到第一个屏幕?
我是说想要的效果是,一次点击使我们从第一个屏幕转到第二个屏幕,第二次点击应该使我们从第二个屏幕回到第一个屏幕。跨度>
【参考方案1】:
我这样做的方法是将其中一个约束的priority
设置得较低,因此它是“可选的”,例如UILayoutPriorityDefaultHigh
,甚至更高,例如999.
然后您可以同时激活两个约束,所需的约束将优先。
要设置它,为默认状态设置必需的约束,为按钮按下状态设置可选的约束。
您可以从激活两个约束开始,然后当按下按钮时,您只需禁用(设置constraint.active = NO
)所需的约束,另一个将优先。当再次按下按钮时,您只需重新启用所需的约束即可。
【讨论】:
我刚刚尝试过这种方式,但我仍然遇到同样的问题。当我重新启用所需的约束时,视图中的所有其他项目都保持不变,并且 UILabel 移动到它下方的项目和topView
项目之间的点。【参考方案2】:
我想通了。发生的事情是 UILabel 的高度没有受到约束,因此当第二个约束被停用并且第一个约束重新激活时,高度会自动增加(见下图)。为了解决这个问题,我必须手动限制所有视图项的高度。如果有人有更好的解决方案,请发布它,因为我不希望手动设置每个项目的高度,因为这可能会导致布局在不同设备上中断。
更新
感谢 siburb 指出 UI 元素的 Content Hugging Priority
属性。我的问题的根源是没有设置这个属性,这允许我的 UILabel 的高度扩大。解决方案是将此属性设置为 750 或更高的值。
[myLabel setContentHuggingPriority:750 forAxis:UILayoutConstraintAxisVertical];
【讨论】:
您不必手动限制高度。您应该只增加标签的Content Hugging Priority
,以便它们在不超出其固有内容大小时更加自信。最初尝试超过 750,但您可能需要增加到“必需”或 1000。
感谢您的建议。我不知道 UI 元素上的 Content Hugging Priority
属性。这绝对是我问题的根源,谢谢。
@Michael 如果您现在有解决方案,请修改您的答案以反映它。以上是关于以编程方式更改 UILabel 上的约束打破布局的主要内容,如果未能解决你的问题,请参考以下文章
UIScrollview 内的 UIView 内的 UILabel 上的 UIGestureRecognizer