在以编程方式创建视图时,我应该在哪里设置自动布局约束

时间:2013-10-15 18:03:18

标签: ios cocoa-touch autolayout

我看到设置约束的不同示例。有些人将它们设置在viewDidLoad / loadView中(在添加子视图之后)。其他人在方法updateViewConstraints中设置它们,由viewDidAppear调用。

当我尝试在updateViewContraints中设置约束时,布局可能会出现跳跃,例如视图出现前稍有延迟。另外,如果我使用这种方法,我应该首先清除现有的约束,即[self.view [removeConstraints:self.view.constraints]

9 个答案:

答案 0 :(得分:101)

我在viewDidLoad / loadView设置我的约束(我的目标是iOS> = 6)。 updateViewConstraints对于更改约束的值很有用,例如如果某些约束取决于屏幕的方向(我知道,这是一种不好的做法),您可以在此方法中更改其constant

在会话期间显示viewDidLoad中的约束“iOS和OS X自动布局简介”(WWDC 2012),从39:22开始。我认为这是讲座中所说的那些事情之一,但不会出现在文档中。

更新:我注意到在Resource Management in View Controllers中提到设置约束:

  

如果您更喜欢以编程方式创建视图,而不是使用   故事板,您可以通过覆盖视图控制器loadView来实现   方法。您对此方法的实现应执行以下操作:

     

(...)

     

3.如果您使用的是自动布局,会为每个布局分配足够的约束   您刚刚创建的视图来控制您的位置和大小   视图即可。否则,实施viewWillLayoutSubviews和   调整子视图框架的viewDidLayoutSubviews方法   视图层次结构。请参阅“调整视图控制器视图的大小。”

更新2 :在WWDC 2015 updateConstraints updateViewConstraints和{{1}}推荐用法期间:

  

实际上,所有这些都是让视图有机会及时更改约束以便下一次布局传递的方法,但实际上通常并不需要。

     

理想情况下,所有初始约束设置都应该在Interface Builder中进行。

     

或者,如果您确实发现需要以编程方式分配约束,那么像viewDidLoad这样的地方要好得多。

     

更新约束实际上只适用于需要定期重复的工作。

     

此外,当您发现需要这样做时,更改约束非常简单;然而,如果你将这个逻辑与其他与之相关的代码区分开来,并将它移动到一个稍后执行的单独方法中,那么你的代码就会变得更加难以理解,因此你将难以维护,其他人理解起来要困难得多。

     

那么什么时候需要使用更新约束?

     

嗯,归结为性能。

     

如果您发现只是更改约束的速度太慢,那么更新约束可能会帮助您解决问题。

     

事实证明,在更新约束中更改约束实际上比在其他时间更改约束更快。

     

原因是因为引擎能够将此传递中发生的所有约束更改视为批处理。

答案 1 :(得分:33)

我建议创建一个BOOL并在UIView的-updateConstraints中设置它们(或-updateViewConstraints,用于UIViewController)。

-[UIView updateConstraints] :(苹果文档)

  

自行设置约束的自定义视图应该通过覆盖此方法来实现。

在视图的生命周期内,-updateConstraints-updateViewConstraints都可能被多次调用。 (例如,在视图上调用setNeedsUpdateConstraints将触发此操作。)因此,您需要确保阻止创建和激活重复约束 - 使用BOOL仅执行某些约束设置,或者在创建&之前确保停用/删除现有约束。激活新的。

例如:

  - (void)updateConstraints {  // for view controllers, use -updateViewConstraints

         if (!_hasLoadedConstraints) {
              _hasLoadedConstraints = YES;
             // create your constraints
         }
         [super updateConstraints];
    }

在评论中向@fresidue干杯,指出Apple的文档建议调用super作为最后一步。如果在更改某些约束之前调用super,则可能会遇到运行时异常(崩溃)。

答案 2 :(得分:4)

这应该在ViewDidLoad中完成,根据Apple的WWDC视频和文档。

不知道为什么人们会推荐updateConstraints。如果你在updateConstraints中进行操作,你将会遇到NSAutoresizingMaskLayoutConstraint的问题并自动调整大小,因为你的视图已经考虑了自动掩码。您需要在updateConstraints中删除它们才能完成工作。

UpdateConstraints应该就是这样,当你需要更新'他们,从您的初始设置进行更改等。

答案 3 :(得分:1)

我有这个解决方案在加载故事板中的人之前更改约束。 此解决方案在加载视图后删除任何滞后。

-(void)updateViewConstraints{

    dispatch_async(dispatch_get_main_queue(), ^{

            //Modify here your Constraint -> Activate the new constraint and deactivate the old one

            self.yourContraintA.active = true;
            self.yourContraintB.active= false;
            //ecc..
           });

    [super updateViewConstraints]; // This must be the last thing that you do here -> if! ->Crash!
}

答案 4 :(得分:1)

您也可以在 viewWillLayoutSubviews:中设置它们:

 override func viewWillLayoutSubviews() {

    if(!wasViewLoaded){
        wasViewLoaded = true

        //update constraint

        //also maybe add a subview            
    }
}

答案 5 :(得分:1)

在视图中执行布局子视图方法

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
}

答案 6 :(得分:0)

这对我有用:

Swift 4.2

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

// Modify your constraints in here

  ...

}

尽管说实话,我不确定是否值得。加载似乎比viewDidLoad()慢。我只是想将它们从后者中移出,因为它越来越大。

答案 7 :(得分:0)

下面的示例是将任何视图传递给另一个类。从情节提要中创建视图

Swift 5.0

    override func viewWillAppear(_ animated: Bool) {
        
      super.viewWillAppear(animated) 
        DispatchQueue.main.async {
            self.abcInstance = ABC(frame: self.myView.frame)
          } 
      }

 

如果您错过了DispatchQueue.main.async,将需要一些时间来更新viewWillAppear中的约束。在情节提要中创建myView并赋予与屏幕宽度和高度相同的约束,然后尝试打印myView的框架。它将在DispatchQueue.main.async或viewDidAppear中给出准确的值,但在没有DispatchQueue.main.async的viewWillAppear中给出准确的值。

答案 8 :(得分:0)

viewWillLayoutSubviews() 中添加您的约束以编程方式添加约束

请参阅自定义布局部分中的Apple Documentation

<块引用>

如果可能,请使用约束来定义您的所有布局。这 生成的布局更健壮且更易于调试。你应该只 覆盖 viewWillLayoutSubviews 或 layoutSubviews 方法时 需要创建一个不能用约束来表达的布局 一个人。