我什么时候可以激活/停用布局约束?

时间:2014-12-15 22:46:02

标签: ios swift uiview autolayout nslayoutconstraint

我在IB中设置了多组约束,我想根据某些状态以编程方式在它们之间切换。有一个constraintsA出口集合,所有出口集合都标记为从IB安装,并且constraintsB出口集合全部在IB中卸载。

我可以通过编程方式在两组之间切换,如下所示:

NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)

但是......当这样做时,我无法弄明白。似乎我应该能够在viewDidLoad中做到这一点,但我无法让它发挥作用。我在设置约束后尝试调用view.updateConstraints()view.layoutSubviews(),但无济于事。

我确实发现如果我在viewDidLayoutSubviews中设置约束,一切都按预期工作。我想我想知道两件事......

  1. 为什么我会出现这种行为?
  2. 是否可以从viewDidLoad激活/停用约束?

8 个答案:

答案 0 :(得分:160)

我在NSLayoutConstraints中激活和停用viewDidLoad,我没有遇到任何问题。所以它确实有效。您的应用和我的应用之间的设置必须有所不同: - )

我只是描述我的设置 - 也许它可以给你带头:

  1. 我为激活/停用所需的所有约束设置了@IBOutlets
  2. ViewController中,我将约束保存到非弱的类属性中。原因是我发现在停用约束后,我无法重新激活它 - 它是零。因此,它似乎在停用时会被删除。
  3. 我不像您一样使用NSLayoutConstraint.deactivate/activate,而是使用constraint.active = YES / NO代替。
  4. 设置约束后,我调用view.layoutIfNeeded()

答案 1 :(得分:39)

也许您可以检查@properties,将weak替换为strong

有时它是因为active = NO设置了self.yourConstraint = nil,因此您无法再次使用self.yourConstraint

答案 2 :(得分:27)

override func viewDidLayoutSubviews() {
// do it here, after constraints have been materialized
}

答案 3 :(得分:14)

我认为您遇到的问题是由于在调用AF viewDidLoad()之前没有将约束添加到其视图中。您有很多选择:

A)您可以将布局约束连接到IBOutlet,并通过这些引用在代码中访问它们。由于在viewDidLoad()开始之前连接了出口,因此应该可以访问约束,并且可以继续在那里激活和停用它们。

B)如果您希望使用UIView的constraints()函数来访问各种约束,您必须等待viewDidLayoutSubviews()启动并执行此操作,因为这是从笔尖创建视图控制器之后的第一点,它将具有任何已安装的约束。不要忘记在完成后致电layoutIfNeeded()。这样做的缺点是,如果要应用任何更改,布局传递将执行两次,并且您必须确保不会触发无限循环。

快速警告: constraints() 方法不会返回已禁用的约束!这意味着如果您要禁用约束以便稍后再打开它,则需要保留对它的引用。

C)您可以忘记故事板方法并手动添加约束。由于您在viewDidLoad()中执行此操作,我认为目的是仅在对象的整个生命周期内执行一次而不是动态更改布局,因此这应该是可接受的方法。

答案 4 :(得分:9)

您还可以将priority属性调整为"启用"和"禁用"它们(750值启用,250禁用例如)。出于某种原因,更改active BOOL对我的UI没有任何影响。不需要layoutIfNeeded,可以在viewDidLoad或之后的任何时间设置和更改。

答案 5 :(得分:7)

停用未使用的约束的适当时间:

-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    self.myLittleConstraint.active = NO;
}

请记住viewWillLayoutSubviews可以被多次调用,所以这里没有繁重的计算,好吗?

注意:如果您希望稍后对某些约束进行反应,则始终将strong引用存储到它们中。

答案 6 :(得分:1)

我发现只要你在覆盖- (void)updateConstraints(目标c)中设置每个法线的约束,并使用strong参考初始使用的活动和非活动约束。在视图周期的其他位置停用和/或激活您需要的内容,然后调用layoutIfNeeded,您应该没有问题。

主要的不是不断重复使用updateConstraints的覆盖并分离约束的激活,只要在第一次初始化和布局后调用updateConstraint s即可。在视图循环中的位置之后似乎很重要。

答案 7 :(得分:0)

创建视图时,将按顺序调用以下生命周期方法:

  1. 的loadView
  2. viewDidLoad中
  3. viewWillAppear中
  4. viewWillLayoutSubviews
  5. viewDidLayoutSubviews
  6. viewDidAppear
  7. 现在回答你的问题。

      
        
    1. 为什么我会出现这种行为?
    2.   

    答案:因为当您尝试在viewDidLoad中设置视图的约束时,视图没有其边界,因此无法设置约束。仅在viewDidLayoutSubviews之后才能最终确定视图的界限。

      
        
    1. 是否可以从viewDidLoad激活/停用约束?
    2.   

    答案:不。上面解释的原因。