2013-10-15 33 views
67

我看到設置約束條件的不同示例。有些設置在viewDidLoad/loadView(子視圖添加後)。其他人則使用方法updateViewConstraints來設置它們,該方法被viewDidAppear調用。我應該在以編程方式創建視圖時設置自動佈局約束條件

當我嘗試在updateViewContraints中設置約束條件時,可能會出現佈局跳動,視圖出現之前略有延遲。另外,如果我使用這種方法,我應該先清除現有的約束條件,即[self.view [removeConstraints:self.view.constraints]

+1

我已經與updateViewConstraints相同的經歷,所以我停止嘗試使用它。我在viewDidLoad中配置約束,或者在自定義視圖的updateConstraints方法中配置約束。希望有人會給你一個明確的答案。 – bilobatum

+1

'updateViewConstraints':*您可以在子類中重寫此方法,以便爲視圖或其子視圖添加約束。*(來自[Apple docs](https://developer.apple.com/library/ios/documentation /Uikit/reference/UIViewController_Class/index.html#//apple_ref/occ/instm/UIViewController/updateViewConstraints)) – testing

回答

94

我在viewDidLoad/loadView(我針對iOS> = 6)中設置了我的約束條件。 updateViewConstraints對於改變約束的值是有用的,例如,如果某些約束依賴於屏幕的方向(我知道,這是一個不好的做法),您可以在此方法中更改它的constant

在會話「iOS和OS X的自動佈局簡介」(WWDC 2012)期間,從39:22開始顯示在viewDidLoad中添加約束。我認爲這是在講座中所說的那些東西之一,但不在文件中。

更新:我注意到在Resource Management in View Controllers建立約束提到:

如果您希望以編程方式創建視圖,而不是使用 故事板,您可以通過重寫你的視圖控制器的這樣做loadView 方法。你的這個方法的實現應該做到以下幾點:

(...)

3.如果您使用自動佈局,分配足夠的約束,以每 剛創建控制倉位的意見和你的尺寸 意見。否則,請執行viewWillLayoutSubviewsviewDidLayoutSubviews方法來調整視圖層次結構中子視圖的框架。請參見「調整視圖控制器的意見。」

更新2:WWDC 2015 updateConstraintsupdateViewConstraintsApple gave a new explanation在推薦用法:

真的,這一切都是對的觀點有辦法有機會在下一次佈局階段及時更改約束條件,但通常不需要它。

所有初始約束設置都應該在Interface Builder中理想地發生。

或者,如果您確實發現需要以編程方式分配約束,則類似viewDidLoad的地方會更好。

更新約束只針對需要定期重複的工作。

此外,這是非常簡單的,只是改變的限制,當你發現需要做;而如果您將該邏輯從與其相關的其他代碼中分離出來,並將其移入單獨的方法,稍後再執行,則代碼變得難以遵循,因此您將難以維護對於其他人來說,理解起來要困難得多。

所以,當你會需要使用更新約束?

好,把它歸結爲性能。

如果您發現只是改變你的地方是制約太慢,然後更新約束也許能幫助你。

事實證明,改變更新約束內部約束是實際上比在其他時間變化的約束更快。

的原因是因爲發動機是能治療這個通作爲一個批次中發生的所有約束的變化。

+2

+1這是最好的答案。 Apple規定loadView作爲設置初始約束的正確位置,並且這不需要在updateConstraints方法中使用額外的BOOL標誌(這看起來很詭異)。 – awolf

+4

我認爲視圖應該對約束負責,而不是視圖控制器。在許多情況下,視圖控制器甚至不知道視圖中的所有元素(例如,表視圖單元格中的靜態標籤)。 – dasdom

+1

@dasdom視圖如何控制與其他視圖的關係?您必須在ViewController中設置約束條件,如「@」| - [button1] - [button2] - |「',對吧?還是有不同的方式? – Joseph

31

我建議創建一個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爲指出,蘋果的文檔建議您調用super作爲最後一步。如果在更改某些約束之前調用super,則可能會遇到運行時異常(崩潰)。

+6

我不確定它是否實際上有所作爲,但文檔中提到'重要:調用[super updateConstraints]作爲實現的最後一步。' – fresidue

+0

乾杯夥計,我會更新我的答案。 – BooRanger

+0

根據文檔,如果您在運行時更改視圖並使您的約束無效,那麼系統會立即刪除該約束並調用setNeedsUpdateConstraints。在執行新佈局之前,系統會調用updateConstraints,您可以在其中定製無效佈局。因此,我可能不會在這個方法上設置一個標誌,這可能會阻止系統調用它。 – smileBot

0

我有這個解決方案來改變在故事板中的人加載之前的約束。 該解決方案刪除視圖加載後的所有滯後。

-(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! 
} 
0

您可以設置它們viewWillLayoutSubviews:太:

override func viewWillLayoutSubviews() { 

    if(!wasViewLoaded){ 
     wasViewLoaded = true 

     //update constraint 

     //also maybe add a subview    
    } 
} 
0

做,在視圖沒有佈局子視圖方法

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 
} 
相關問題