2013-06-27 49 views
1

所以我有兩個矩形視圖和一個將它們連接在一起的視圖。參見圖表http://cl.ly/image/340Q1l381b3L自動佈局和在兩個其他視圖之間居中視圖

是否可以限制紅色視圖,使其保持在綠色視圖的垂直範圍內?我想保持它在重疊區域居中。

雖然這不會使它保持居中,但我認爲我只能將以下兩個約束應用於綠色視圖和紅色視圖,以至少保持紅色視圖綁定到綠色視圖。

[NSLayoutConstraint 
constraintWithItem:redView 
attribute:NSLayoutAttributeCenterY 
relatedBy:NSLayoutRelationGreaterThanOrEqual 
toItem:greenView 
attribute:NSLayoutAttributeBottom 
multiplier:1.0f 
constant:0.0f]; 

[NSLayoutConstraint 
constraintWithItem:redView 
attribute:NSLayoutAttributeCenterY 
relatedBy:NSLayoutRelationLessThanOrEqual 
toItem:greenView 
attribute:NSLayoutAttributeTop 
multiplier:1.0f 
constant:0.0f]; 

但是這導致

2013年6月26日22:13:27.493 MiniMeasure [25896:303]無法同時滿足約束: ( 「NSLayoutConstraint:0x1002cebf0 RedView:0x1002cdf90。 centerY> = GREENVIEW:0x1018a34c0.bottom」, 「NSLayoutConstraint:0x1002cf720 RedView:0x1002cdf90.centerY < = GREENVIEW:0x1018a34c0.top」, 「NSLayoutConstraint:0x1002bb1e0五:[綠景:0x1018a34c0(157)]」 )將嘗試通過打破約束NSLa來恢復youtConstraint:0x1002bb1e0五:[綠景:0x1018a34c0(157)]

所以很明顯它不喜歡的綠色觀點,即一個具有高度限制,並試圖打破它。但我需要綠色的意見來維持它們的大小。兩個綠色視圖都有寬度和高度限制。

有什麼想法/建議嗎?

謝謝!

+0

你能夠得到你期待他們的綠色的嗎?他們移動嗎? – uchuugaka

+0

是的。綠色的只能使用約束來移動和調整大小。這是我遇到麻煩的紅色視圖。 –

+0

我的意思是他們並不總是處於相同的相對位置?如果是這樣,它可能會很複雜,但我可以考慮一些解決方案。 – uchuugaka

回答

0

根據註釋,一種解決方案是不對紅色矩形使用自動佈局,而是僅在超級視圖或與超級視圖相同的幀矩形的子視圖中使用drawRect。

首先使用KVO通知更改綠色rects的框架我們邊界(如適用於您的實現)

改變?

如果你在兩個綠色矩形上使用NSUnionRect,幾條if語句可以告訴你是否顯示紅色矩形,並提供繪製或定位矩形的邏輯。

如果聯合矩形大於一個方向的綠色矩形和另一個方向的綠色矩形的總和,則繪製一個紅色矩形。

哪裏可以通過比較它們的邊緣來繪製。

僞代碼 如果unionRect.size.x>(greenRect1.size.x + greenRect2.size.x)AND unionRect.size.y <(greenRect1.size.y + greenRect2.size.y) 然後在它們之間水平地繪製紅色矩形。 現在計算紅色矩形的矩形。

您可以使用這種相同的方法找出相對於綠色矩形的紅色矩形的約束,但這實際上會增加複雜性。

我不相信所有東西都屬於自動佈局,因爲工作量和複雜性以及潛在的意義混淆。

+0

所以我現在有一個工作解決方案,只需將框架設置在紅色矩形上,但我的整個應用程序是自動佈局它只是覺得很髒。我只是想知道我是否錯過了一些東西,但我認爲你是對的......在這種情況下使用自動佈局會增加複雜性。感謝您的反饋! –

+0

但是請看看Rob的帖子。這是有啓發性的。 – uchuugaka

+0

但我認爲訣竅是實用主義。蘋果正在推動自動佈局,並不一定是一切的最佳解決方案。我也在學習。 – uchuugaka

11

你可以通過自動佈局得到你想要的。演示:

demo

但是,如果綠色的觀點沒有任何垂直重疊,結果可能不是你想要什麼:

enter image description here

所以,我怎麼辦呢?

首先,有五種觀點。有窗口的內容視圖,兩個可拖動的綠色視圖,文本字段(「中心」)和棕褐色間隔視圖。可拖動的視圖,文本字段和間隔符都是窗口內容視圖的直接子視圖。特別地,文本字段是而不是間隔視圖的子視圖。

其次,我需要設置一些約束優先,所以我定義了一個輔助函數:

static NSLayoutConstraint *constraintWithPriority(NSLayoutConstraint *constraint, 
    NSLayoutPriority priority) 
{ 
    constraint.priority = priority; 
    return constraint; 
} 

接下來,我創建了左拖動視圖。我爲X的位置和寬度,高度和Y位置設置了限制。

- (void)createLeftView { 
    leftView = [[DraggableView alloc] init]; 
    leftView.translatesAutoresizingMaskIntoConstraints = NO; 
    [rootView addSubview:leftView]; 

    NSDictionary *views = NSDictionaryOfVariableBindings(leftView); 
    [rootView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:|-(20)-[leftView(80)]" 
     options:0 metrics:nil views:views]]; 
    [leftView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:[leftView(120)]" 
     options:0 metrics:nil views:views]]; 
    leftView.yConstraint = [NSLayoutConstraint 
     constraintWithItem:leftView attribute:NSLayoutAttributeTop 
     relatedBy:NSLayoutRelationEqual 
     toItem:rootView attribute:NSLayoutAttributeTop 
     multiplier:1 constant:20]; 
    [rootView addConstraint:leftView.yConstraint]; 
} 

注意,我DraggableView類處理鼠標通過調整其yConstraint的不斷拖累。由於我需要訪問Top約束,因此我直接設置了該約束,而不是使用可視格式。

創建右拖動視圖非常相似,不同之處在於它錨定到根視圖的後緣。

- (void)createRightView { 
    rightView = [[DraggableView alloc] init]; 
    rightView.translatesAutoresizingMaskIntoConstraints = NO; 
    [rootView addSubview:rightView]; 

    NSDictionary *views = NSDictionaryOfVariableBindings(rightView); 
    [rootView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:[rightView(80)]-(20)-|" 
     options:0 metrics:nil views:views]]; 
    [rightView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:[rightView(120)]" 
     options:0 metrics:nil views:views]]; 
    rightView.yConstraint = [NSLayoutConstraint 
     constraintWithItem:rightView attribute:NSLayoutAttributeTop 
     relatedBy:NSLayoutRelationEqual 
     toItem:rootView attribute:NSLayoutAttributeTop 
     multiplier:1 constant:20]; 
    [rootView addConstraint:rightView.yConstraint]; 
} 

現在出現棘手的部分。我創建了一個額外的視圖,我稱之爲間隔器。我已經將該視圖留下了,以便更容易理解此演示的工作原理。通常情況下,你會隱藏隔離層;隱藏的意見仍然參與佈局。

- (void)createSpacerView { 
    spacerView = [[SpacerView alloc] init]; 
    spacerView.translatesAutoresizingMaskIntoConstraints = NO; 
    [rootView addSubview:spacerView]; 

spacer的水平約束很簡單。間隔器的前緣固定在左側可拖動視圖的後緣,間隔器的後緣固定在右側可拖動視圖的前緣。因此,間隔器總是精確地跨越可拖動(綠色)視圖之間的水平間隙。

NSDictionary *views = NSDictionaryOfVariableBindings(leftView, rightView, spacerView); 
    [rootView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"H:[leftView][spacerView][rightView]" 
     options:0 metrics:nil views:views]]; 

接下來,我們限制間隔件的頂部和底部的邊緣爲等於根視圖的頂部和底部邊緣,但與優先級1(非常低的優先級):

[rootView addConstraints:[NSLayoutConstraint 
     constraintsWithVisualFormat:@"V:|-([email protected])-[spacerView]-([email protected])-|" 
     options:0 metrics:nil views:views]]; 

然後我們進一步約束所述間隔的頂部邊緣爲大於或等於兩個可拖動的觀點頂部邊緣的頂部邊緣,優先級爲2(幾乎極低):

[rootView addConstraint:constraintWithPriority([NSLayoutConstraint 
     constraintWithItem:spacerView attribute:NSLayoutAttributeTop 
     relatedBy:NSLayoutRelationGreaterThanOrEqual 
     toItem:leftView attribute:NSLayoutAttributeTop 
     multiplier:1 constant:0], 2)]; 
    [rootView addConstraint:constraintWithPriority([NSLayoutConstraint 
     constraintWithItem:spacerView attribute:NSLayoutAttributeTop 
     relatedBy:NSLayoutRelationGreaterThanOrEqual 
     toItem:rightView attribute:NSLayoutAttributeTop multiplier:1 constant:0], 2)]; 

所以間隔件的頂邊有三個約束:

  • spacerView.top == rootView.top優先級爲1
  • spacerView.top> = leftView。頂部優先級爲2
  • spacerView.top> = rightView.top優先級爲2

這些約束相結合,把間隔物的頂部邊緣儘可能地高,而不是上面的兩個可拖動的觀點的頂部邊緣。因此隔離物頂部邊緣將等於可拖動視圖的頂部邊緣中較低的邊緣。

我們需要在這裏使用低優先級,因爲自動佈局會拒絕使墊片的高度爲負值。如果我們使用優先級1000(默認值),自動佈局將開始調整可拖動視圖的大小,以強制它們始終有一些垂直重疊。

我們建立了在隔板的底部邊緣類似的限制:

[rootView addConstraint:constraintWithPriority([NSLayoutConstraint 
     constraintWithItem:spacerView attribute:NSLayoutAttributeBottom 
     relatedBy:NSLayoutRelationLessThanOrEqual 
     toItem:leftView attribute:NSLayoutAttributeBottom 
     multiplier:1 constant:0], 2)]; 
    [rootView addConstraint:constraintWithPriority([NSLayoutConstraint 
     constraintWithItem:spacerView attribute:NSLayoutAttributeBottom 
     relatedBy:NSLayoutRelationLessThanOrEqual 
     toItem:rightView attribute:NSLayoutAttributeBottom 
     multiplier:1 constant:0], 2)]; 
} 

因此間隔將始終跨越的意見拖動垂直重疊,如果重疊。如果沒有重疊,自動佈局會打破一些約束,以避免給予墊片負高度。間隔將以0的高度結束,固定到可拖動視圖的近邊緣之一。

最後,我設置的文本字段中以保持在間隔水平和垂直方向上居中:

- (void)createMiddleView { 
    middleView = [[NSTextField alloc] init]; 
    middleView.translatesAutoresizingMaskIntoConstraints = NO; 
    middleView.stringValue = @"Center"; 
    [middleView setEditable:NO]; 
    [middleView setSelectable:NO]; 
    [rootView addSubview:middleView]; 

    [rootView addConstraint:[NSLayoutConstraint 
     constraintWithItem:middleView attribute:NSLayoutAttributeCenterX 
     relatedBy:NSLayoutRelationEqual 
     toItem:spacerView attribute:NSLayoutAttributeCenterX 
     multiplier:1 constant:0]]; 
    [rootView addConstraint:[NSLayoutConstraint 
     constraintWithItem:middleView attribute:NSLayoutAttributeCenterY 
     relatedBy:NSLayoutRelationEqual 
     toItem:spacerView attribute:NSLayoutAttributeCenterY 
     multiplier:1 constant:0]]; 
} 

對於所有的五個視圖(包括根視圖)之間的這些限制,自動佈局保持中間視圖以您請求的方式爲中心。

我不確定在Xcode 4.6.3中是否可以在nib中設置這樣的約束條件。如果可能的話,我相信這是非常痛苦的。

你可以找到我的完整演示項目源代碼in this github repository。我在Xcode 5-DP2中創建了這個項目。

+0

令人敬畏的教程。對於Xcode 4版本來說會更令人敬畏......;)不幸的是,它強調了自動佈局的真正困難程度,這在很大程度上取決於可可的年輕化程度。它確實使CoreData看起來很容易。 – uchuugaka

+0

如果將源文件複製到在Xcode 4中創建的新項目中,源文件應該可以工作。 –

+0

True true。這是n that的鬍鬚。 BTW +100的GIF:D – uchuugaka

相關問題