你可以通過自動佈局得到你想要的。演示:
但是,如果綠色的觀點沒有任何垂直重疊,結果可能不是你想要什麼:
所以,我怎麼辦呢?
首先,有五種觀點。有窗口的內容視圖,兩個可拖動的綠色視圖,文本字段(「中心」)和棕褐色間隔視圖。可拖動的視圖,文本字段和間隔符都是窗口內容視圖的直接子視圖。特別地,文本字段是而不是間隔視圖的子視圖。
其次,我需要設置一些約束優先,所以我定義了一個輔助函數:
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中創建了這個項目。
你能夠得到你期待他們的綠色的嗎?他們移動嗎? – uchuugaka
是的。綠色的只能使用約束來移動和調整大小。這是我遇到麻煩的紅色視圖。 –
我的意思是他們並不總是處於相同的相對位置?如果是這樣,它可能會很複雜,但我可以考慮一些解決方案。 – uchuugaka