启用和禁用自动布局约束

35

我有一个简单(我认为如此)的问题:我有一个UIImageView,在Storyboard中已经设置多个约束。

有时,我需要禁用这些约束,并手动设置其frame,但稍后,我想重新启用这些约束,并使视图返回到由约束决定的位置。

我以为可以通过类似以下的方法实现:

@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var constraint: NSLayoutConstraint!

func example() { 

    //to set its location and size manually
    imageView.removeConstraint(constraint) 
    imageView.frame = CGRectMake(...)

    //to cause it to return to its original position
    imageView.addConstraint(constraint) 

}

然而,我遇到了这个错误:2015-08-26 01:14:55.417 Constraints[18472:923024] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7fbb72815f90 V:[_UILayoutGuide:0x7fbb72814c20]-(100)-[UIImageView:0x7fbb72814540]>。有人知道为什么会出现这个错误吗?

通过调用self.view.addConstraint(...)将约束添加到view中可以消除错误,但仍无法将图像视图放回其原本的位置。

我注意到,我甚至不必删除或取消激活约束就能够轻松设置imageView的框架,只要不调用setTranslatesAutoresizingMaskIntoConstraints(true)即可。

我已经看过这个问题,但答案似乎过于复杂,也许已经过时,甚至不适用。

我还看到了这个问题,但它只覆盖了如何禁用约束--没有涉及如何重新启用它们。

尝试设置active属性:

self.top.active = false
self.right.active = false
self.bottom.active = false
self.left.active = false
    
imageView.frame = CGRectMake(100, 100, 100, 100)

这实际上只是导致imageView不再可见。 (但如果我不将所有约束的active属性设置为false,则imageView会移动到正确的位置。

然而,真正的问题是,当我尝试通过将所有约束的active属性设置为true来使图像视图返回原位时,什么都没有发生——imageView仍停留在原地(在本例中由imageView.frame = CGRectMake(100, 100, 100, 100)指定)。

此外,根据我的测试和Joachim Bøggild在这里的答案,当约束的active属性设置为false时,该约束变为nil,因此无法重新激活。

将约束添加到数组并激活/停用它们:

有趣的是,这几乎与设置active属性完全相同。将所有约束放入一个数组array,然后调用NSLayoutConstraint.deactivateConstraints(array)将使图像视图消失。此外,稍后使用NSLayoutConstraint.activateConstraints(array)重新激活约束并不能使图像视图返回到应该在的位置——它仍停留在原地。

3个回答

71

哦!

一旦将限制条件的active属性设置为false,它们就会变成零(因此无法重新激活),将它们作为强引用保留(感谢Caleb澄清术语)可以使它们随意激活和停用。


2
如果有人想知道如何使 IBOutlet 强引用:只需删除 weak 关键字,然后你的引用就是强引用了! - LinusGeffarth

35
如果您查看NSLayoutConstraint的文档,您会发现一个名为激活和取消约束的部分,其中描述了active属性,该属性告诉您:
您可以通过更改此属性来激活或取消约束...激活或取消约束会在管理此约束的项目的最近公共祖先视图上调用addConstraint:和removeConstraint:。请使用此属性,而不是直接调用addConstraint:或removeConstraint:。
当你已经得到了与所涉及的约束相关的strong引用(例如你的输出口),你可以简单地将其active属性设置为false(或在Obj-C中为NO)以禁用,或者设置为true(或YES)以启用。

嗨,Caleb,感谢您的建议!我尝试了这个方法,但遇到了一些问题,我在上面进行了描述。 - Randoms
2
似乎当约束条件的 active 属性被设置为 false 时,该约束条件会变成 nil,因此无法重新激活。 - Randoms
5
好的,理解了。将约束条件的输出设置为强类型后,问题得到解决——我现在可以正确地激活和停用它们。 - Randoms
3
强制引用,而非强类型引用。这是有道理的,因为文档中表示更改 active 属性会移除约束,也就是说原先附着在视图上的约束将不再存在。如果没有强制引用,约束将被释放。将输出口设为强引用可以避免这种情况。 - Caleb
6
“@Randoms 让插座更加‘稳固’实际上是正确的答案,至少对我来说是这样。您应该将其发布为答案,而不是作为难以找到的评论。或者将其作为问题本身的一部分进行更新。” - i4niac
@i4niac 已修复:D - Iulian Onofrei

1
从Storyboard将约束作为IBOutlet连接到ViewController,并创建一个数组将所有约束添加到数组中。
当不使用时取消这些约束。
每当需要时添加约束。
NSLayoutConstraint *constraint1;
NSLayoutConstraint *constraint2;
NSLayoutConstraint *constraint3;
NSArray *arr = @[constraint1,constraint2,constraint3];
 [NSLayoutConstraint deactivateConstraints:arr];

//After deactivate constraint array add what ever frame you want to add

//Activate  lateroN
[NSLayoutConstraint activateConstraints:arr];

嗨,Kavita Asija,我也尝试了这个,不过是用Swift实现的,但遇到了一些问题,我已在上面的编辑中添加了。 - Randoms
  • (void)updateConstraintsIfNeeded
  • (void)updateConstraints
  • (BOOL)needsUpdateConstraints
  • (void)setNeedsUpdateConstraints
在应用活动和取消约束后更新视图约束。
- Kavita

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接