2012-06-29 53 views
21

我應該如何在NSSplitView子視圖中使用自動佈局約束?NSSplitView和自動佈局

NSSplitView子視圖有3子視圖:topPanetableContainerbottomPane和我這樣設置約束:

NSDictionary* views = NSDictionaryOfVariableBindings(topPane, tableContainer, bottomPane); 

for (NSView* view in [views allValues]) { 
    [view setTranslatesAutoresizingMaskIntoConstraints:NO]; 
} 

[myView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[topPane(34)][tableContainer][bottomPane(24)]|" 
                   options:0 
                   metrics:nil 
                   views:views]]; 

[mySplitView addSubview:myView]; 

而得到這個控制檯:

Unable to simultaneously satisfy constraints: 
(
    "<NSLayoutConstraint:0x7fd6c4b1f770 V:[NSScrollView:0x7fd6c4b234c0]-(0)-[CPane:0x7fd6c4b2fd10]>", 
    "<NSLayoutConstraint:0x7fd6c4b30910 V:[CPane:0x7fd6c4b2f870(34)]>", 
    "<NSLayoutConstraint:0x7fd6c4b30770 V:|-(0)-[CPane:0x7fd6c4b2f870] (Names: '|':NSView:0x7fd6c4b22e50)>", 
    "<NSLayoutConstraint:0x7fd6c4b212f0 V:[CPane:0x7fd6c4b2fd10]-(0)-| (Names: '|':NSView:0x7fd6c4b22e50)>", 
    "<NSLayoutConstraint:0x7fd6c4b2f910 V:[CPane:0x7fd6c4b2f870]-(0)-[NSScrollView:0x7fd6c4b234c0]>", 
    "<NSLayoutConstraint:0x7fd6c4b21290 V:[CPane:0x7fd6c4b2fd10(24)]>", 
    "<NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]>" 
) 

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fd6c4b1f770 V:[NSScrollView:0x7fd6c4b234c0]-(0)-[CPane:0x7fd6c4b2fd10]> 

我覺得<NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]>原因這一點,但我無法重置自動調整屏蔽,因爲NSSplitView會設置它。

在拆分視圖中使用自動佈局的最佳方法是什麼?有沒有辦法處理分割視圖子視圖的最小/最大大小與自動佈局沒有NSSplitViewDelegate

+0

同樣的問題在這裏。我把所有東西都放在了IB中,而不是編程,但是有類似的調試輸出,包括'NSAutoresizingMaskLayoutConstraint'。 –

+1

這似乎是固定在10.8以下,但是如您在10.7下注意到的那樣破壞了。在10.8中,您可以設置Xcode中分割視圖的內容視圖的最小高度和寬度(無論如何4.5.2)。無法在10.7以下完成此操作,而在10.8中創建的應用程序仍然無法在10.7中正常工作 – Dad

+0

通常需要在10.8以上工作,但大多數視圖的子視圖之間需要指定約束 - 而不是supre - 否則您將得到* Unable以同時滿足*錯誤.. – Jay

回答

0

之後我加載了一個nib文件,然後加載setTranslatesAutoresizingMaskIntoConstraints:NO

所以,也許你應該首先加上[mySplitView addSubview:myView];你的意見,然後禁用自動大小面具的約束到約束的翻譯,然後在myView之後加上你的約束。

編輯:

好吧,看來我missunderstand的MyView的。 您必須將約束添加到子視圖而不是分割視圖。

[topPane addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topPane(34)]" options:0 metrics:nil views:views]]; 

[bottomPane addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[bottomPane(24)]" options:0 metrics:nil views:views]]; 

你不必加邊緣約束(以下簡稱 「|」,在 「V:| [topPane(34)]」),因爲在NSSplitView子視圖已經自動調整。

這導致這個例如對於topPane約束:

Screenshout

注:忽略子視圖的內容,他們只是佔位符

+0

如果我爲'myView'設置'translatesAutoresizingMaskIntoConstraints'爲'NO',分割視圖將無法處理它的大小 - 它不適用於自動佈局。 – Dmitry

1

你不想禁用translatesAutoresizingMaskIntoConstraints可言。你不應該混淆系統視圖約束。 NSSplitView處理單個視圖本身的大小,你基本上試圖將它的控制權移開。更何況,你忘了解釋分離器。

在splitview上設置最小值或最大值(或常量)寬度/高度的正確方法是在視圖上單獨設置這些值。特別是,如果您在代碼中執行此操作,則需要對constraintsWithVisualFormat使用2個單獨的調用,否則視覺格式語言將在視圖之間創建約束。

你可以在IB中完成所有這些工作。您甚至可以在分割視圖中設置每個視圖的優先級,這將導致一個或另一個視圖在窗口執行時調整大小,而不是平均分配調整大小。

+0

有趣的是,你聽到你打算如何在IB中打開AutoLayout來實現這一點.... – Dad

+0

實際上在10.7中不可行 - 在Xcode 4.5.2中,在10.7中禁用了在NSSplitView內容視圖中設置寬度約束的控件如果您在10.8中將其設置爲Xcode,然後在10.7上運行該應用程序,它將在10.7中打破該約束,轉而使用NSAutoresizingMaskLayerConstraint,因此不起作用。 – Dad

4

NSSplitView從一開始就是一件很奇怪的事情,如果它很快就會消失的話,它並不會讓我感到驚訝。在嘗試讓NSSplitView與AutoLayout合作一個月,並從一次絕望攻擊下沉到另一次之後,我終於放棄了。

我的解決方案是根本不使用NSSplitView和AutoLayout。因此,無論是NSSplitView沒有Autolayout還是Autolayout沒有NSSplitView:這不像聽起來那麼複雜:只需將你的子視圖放在一起並添加NSLayoutConstraints作爲IBOutlets。這些約束的常量然後可以在代碼中的控制器中設置和更改。使用這種方法,您可以設置原點(負偏移將其滑出窗口),寬度以及與其他子視圖的關係 - 再加上它非常容易爲視圖的動畫製作動畫約束(曾嘗試過動畫效果 NSSplitView? )

唯一缺少的是鼠標在分隔線上的拖拽,但這可以通過幾行代碼實現,在您的自定義「SplitView」中跟蹤mouseEvents。

有一個蘋果自動佈局「splitview」的例子(不幸只有垂直),我最近在github上看到至少有一個新項目。儘管對於我來說,我認爲從我的自定義解決方案開始,針對我的應用程序的特定需求會更容易,而不是試圖創建非常通用的東西(因而使其處理起來太複雜)。

編輯:我現在完成了我的自定義splitView,它從單獨的筆尖加載它的子視圖。沒有約束問題,沒有自動佈局警告。與整個月努力讓它與NSSplitView一起工作,我現在有一個工作的自定義splitView基於約束,很容易動畫,只在一個晚上創建。我絕對推薦走這條路!

+0

你能分享你的自定義splitView代碼嗎? –

+1

@ Ben-Uri:我在我的[答](http://stackoverflow.com/a/13964486/456851)中有一個小項目,可能對您有用。 –

+0

廢話 - 像AL在10.8+以上的微風工作 – Jay

0

儘管我討厭不同意,但是Auco的答案不應該被評爲最高。用足夠的工作量來解決問題並沒有任何幫助。在我看來,對於那些沒有足夠閱讀文檔的人來說,NSSplitView只是一個問題。

這裏提到的問題的實際解決方案非常簡單:自動佈局在NSSplitView上引入了新的「保持優先級API」。正如文檔所述:將較低的值設置爲子視圖的優先級將使他更有可能較早地佔用寬度。所有這些都可以在IB中以編程方式設置,而不會有任何絕望。需要的工作量:約20秒

+1

如果只是回答問題,而不是對其他回答者和提問者表示這樣的蔑視,那麼這個答案會更有用。我會給你+1的答案和-1的粗魯,所以他們相互取消。 –

+1

@Jacque:如果您還閱讀過文檔,您會看到只有OS X 10.8以上的版本才能使用。當他們正在考慮向後兼容性時,你不需要對其他人不加思索。 –

+1

@Jacque:如果你正在處理一個非常簡單的佈局,比如兩個textView作爲一個splitView的子視圖,那麼你可能是對的。但是,只要需要處理複雜的佈局子視圖,設置保留優先級就沒有多大幫助:使用自動佈局的splitView中的內容會創建自動佈局錯誤,因爲它與自動調整掩碼相沖突。動畫SplitViews是一個令人頭痛的問題,因爲您需要計算幀,這在使用自動佈局時是不行的。只有優先考慮才能解決問題。 – auco

7

我發現,如果我在我的窗口和控制拆分視圖工具欄任何的這種委託方法出現此錯誤:

splitView:constrainMinCoordinate:ofSubviewAt: 
splitView:constrainMaxCoordinate:ofSubviewAt: 
splitView:shouldAdjustSizeOfSubview: 

解決方法是在windowDidLoad中將工具欄附加到窗口中發現的。

+0

我有一個與NSTabView相同的問題,取消選中工具欄上的'Visible at Launch'複選框,然後在'windowDidLoad'中顯示它,確實擺脫了愚蠢的警告。感謝提示。 – DarkDust

+0

在具有最小/最大寬度約束的自動佈局分割視圖中,我遇到了同樣的問題。刪除所有這3個委託方法解決了它。 –

+2

很多關於這個問題的錯誤信息。這個答案是正確的,但工具欄業務是一個紅鯡魚。該問題記錄在AppKit發行說明中(https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKitOlderNotes/index.html#10_11SplitView);某些'NSSplitViewDelegate'方法在自動佈局方面播放不好,不應使用。相反,在'NSSplitView'正下方的'NSView'上設置合適的約束,它應該可以正常工作而不需要記錄。 – bhaller

3

任何人誰在未來絆倒這一點,並正在尋找一個快速啓動到基於約束的NSSplitView替代品,我這裏寫一個小項目試圖重新使用自動佈局NSSplitView的功能部分:

https://github.com/jwilling/JWSplitView

這有點馬車,但它可能是任何人想要走這條路了有益的參考。

0

我花了一些時間讓我的自動佈局清理警告,但我確實得到它在IB(幾個splitviews和子視圖)處理。

我的佈局是這樣的:

RootView
    | - 1 NSSplitView(3個縱子視圖)
            | ----的UIView(左)
            | ---- 第2個NSSplitView(中心& 2水平子視圖)
                      | --- UIView的(頂部)
                      | --- 第三NSSplitView(底部& 3垂直子視圖)
                              | ---的UIView(左)
                              | ---的UIView(中心)
                              | ---的UIView(右)
            | ----的UIView(右)

我的問題是,我在所有子視圖中都有19個警告,但是我的佈局看起來很好,並且它的工作方式應該如此。 經過一段時間,我發現我的警告的原因:在我的第一個分割視圖中的外觀的約束。

這兩個視圖(左和右)都有一個寬度約束,「寬度> = 200」,中間視圖(第二個分割視圖)沒有約束(因爲其子視圖處理的最小寬度和最大寬度) 。

警告告訴我,自動佈局想縮小我的IB-UI佈局,因爲計算的最小寬度比我的佈局小,但我不想縮小它在IB中。

我添加了一個固定的約束「width = 200」給我的第一個splitview的兩個外部子視圖,並勾選了「在構建時刪除」。

現在我的佈局是免費的警告,一切工作應該如何。

我的結論

我想用自動版式和splitviews問題是,自動佈局無法處理子視圖的寬度限制。我們希望使用splitviews的原因是,我們希望動態調整視圖的寬度,並且我們希望在兩個方向上縮小和擴大。

所以沒有寬度< = xxx & & width> = xxx。 Autolayout只能處理其中一個,我們會在IB中收到警告。您可以使用IB中的臨時約束來解決此問題,該問題將在運行時刪除。

我希望它是有道理的,我寫了,但它在我的項目中運行良好。

PS:我無法找到任何解決辦法,直到今天,我發現這個線程..所以我猜你的帖子的啓發我:-)

0

我用這個類作爲一種變通方法,它並不完美(子視圖口吃有點),但它暢通無阻。我使用這個類作爲每個拆分視圖窗格中的自定義類。

@interface FBSplitPaneView : NSView 

@end 

@implementation FBSplitPaneView 

- (void)setFrame:(NSRect)frame 
{ 
    for (NSView *subview in self.subviews) { 
    subview.frame = self.bounds; 
    } 
    [super setFrame:frame]; 
} 

@end