2014-01-21 12 views
7

我正在編寫一個以編程方式初始化的自定義視圖。我重寫updateConstraints以添加此視圖所需的所有約束。 :在約束依賴於框架的自定義視圖中使用自動佈局

- (void)updateConstraints { 
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]]; 

    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeTop multiplier:1 constant:0]]; 
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeBottom multiplier:1 constant:0]]; 

    // some more constraints, you get the point 

    self.bottomSpacingConstraint = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:-(0.2 * CGRectGetHeight(self.bounds))]; 
    [self addConstraint:self.bottomSpacingConstraint]; 

    [super updateConstraints]; 
} 

的問題是,self.bounds返回CGRectZero相當。我做了我的研究,根據這objc.io article,這是預期的,因爲框架不會被設置,直到調用layoutSubviews。它還提到

要強制系統立即更新視圖樹的佈局,可以(分別在iOS和OS X)調用layoutIfNeeded/layoutSubtreeIfNeeded。如果您的後續步驟依賴於視圖的幀更新,這可能會有所幫助。

然而,當我就在updateConstraints設置self.bottomSpacingConstraint前加

[self setNeedsLayout]; 
[self layoutIfNeeded]; 

,我仍然獲得了CGRectZero回來的框架。根據objc.io文章(和這SO answer),這些方法應該觸發佈局和更新框架。

任何人都可以點亮如何使這一切工作?我感興趣的解決方案,以及是什麼原因導致其佈局相關的方法被稱爲解釋(例如,看來,改變現有的約束在layoutSubviews原因setNeedsUpdateConstraints不斷被調用,然後觸發updateConstraints並導致限制要多次添加)。

回答

2

我很確定您不能或不應該從updateConstraints撥打layoutIfNeeded。更新約束是在佈局週期的較早部分,所以我不認爲它會產生你以後的效果。

在你的情況下,解決方案是檢查layoutSubviews中依賴於框架的約束條件的constant屬性,如果需要更新,可以在那裏更新或者致電setNeedsUpdateConstraints(注意導致循環)。

你曾說過更新約束觸發另一個調用updateConstraints - 這是真的,我想你是濫用updateConstraints - 它是更新基於更改您的視圖內容限制。如果它們不存在,則只應添加這些約束。

+1

這是蘋果公司說,大約'updateConstraints':*實現此方法,如果您需要,以創建子視圖之間的自定義約束,*現在,它並沒有明確地說,他們應建立在** **'updateConstraints ',但這就是它所暗示的,我相信。如果不是,我會在哪裏創建這些約束條件? –

+1

我不是說不要在那裏創建它們。我只是說只有在它們不存在時才創建它們,因爲可以多次調用該方法。 – jrturton

+1

不夠公平,但我不想濫用'updateConstraints'。如果該方法是不是真的,我要創建的約束,那麼我完全好創建別的地方。我只是不知道什麼會是一個更好的地方。如果'updateConstraints' * *是正確的地方,我將包裝在檢查其不存在的if語句創建,第一。 –