2012-06-29 21 views
21

Tôi nên sử dụng các ràng buộc bố cục tự động bên trong lớp phủ NSSplitView như thế nào?NSSplitView và autolayout

NSSplitView subview của tôi có 3 subview: topPane, tableContainerbottomPane và tôi đặt ép như thế này:

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]; 

Và có này trong giao diện điều khiển:

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]> 

Tôi nghĩ <NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]> nguyên nhân này, nhưng tôi không thể đặt lại mặt nạ tự động hóa, vì NSSplitView đặt nó.

Cách tốt nhất để sử dụng bố cục tự động trong chế độ xem chia tách là gì? Và có cách nào để xử lý min/tối đa kích thước của subview xem phân chia với bố trí tự động mà không cần NSSplitViewDelegate?

+0

Cùng một vấn đề ở đây. Tôi đặt mọi thứ trong IB thay vì lập trình, nhưng có kết quả gỡ lỗi tương tự, bao gồm 'NSAutoresizingMaskLayoutConstraint'. –

+1

Điều này có vẻ cố định dưới 10.8 nhưng bị hỏng khi bạn lưu ý dưới 10.7. Trong 10.8 bạn có thể thiết lập chiều cao tối thiểu và chiều rộng của các khung nhìn nội dung của chế độ xem chia nhỏ trong Xcode (4.5.2 anyway). Không thể thực hiện điều này dưới 10.7 và các ứng dụng với tính năng này được tạo trong 10.8 vẫn không hoạt động ngay trong 10.7 – Dad

+0

Hoạt động nói chung với 10.8+ nhưng ràng buộc cần phải được chỉ định giữa các lần xem phụ cho hầu hết các lượt xem - chứ không phải supre - hoặc bạn sẽ nhận được * Không thể để đồng thời đáp ứng * lỗi .. – Jay

Trả lời

0

Tôi tải tất cả bằng một tệp nib và setTranslatesAutoresizingMaskIntoConstraints:NO sau đó.

Vì vậy, có lẽ trước tiên bạn nên thêm [mySplitView addSubview:myView]; lượt xem của mình và vô hiệu hóa sau đó dịch mặt nạ tự động hóa thành các ràng buộc và sau đó bạn thêm đường viền của mình vào myView.

EDIT:

Ok có vẻ như tôi missunderstand các MyView. Bạn phải thêm ràng buộc vào các bản xem trước chứ không phải đối với chia tách.

[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]]; 

Bạn không cần phải thêm những hạn chế cạnh (các "|" trong chữ "V: | [topPane (34)]") vì subviews trong NSSplitView đã autoresizing.

Điều này dẫn đến điều này, ví dụ: cho ràng buộc topPane:

Screenshout

Chú ý: bỏ qua nội dung subview, họ chỉ là placeholders

+0

Nếu tôi đặt 'translatesAutoresizingMaskIntoConstraints' thành' NO' cho 'myView', chế độ xem tách sẽ không xử lý kích thước của nó - nó không hoạt động với tính năng tự động trả lời. – Dmitry

1

Bạn không muốn vô hiệu hóa translatesAutoresizingMaskIntoConstraints ở tất cả. Bạn không nên gây rối với các ràng buộc của chế độ xem hệ thống. NSSplitView xử lý kích thước cho từng chế độ xem riêng lẻ và về cơ bản bạn đang cố gắng tách kiểm soát của nó đi. Chưa kể, bạn quên tài khoản cho splitter.

Cách chính xác để đặt chiều rộng/tối đa (hoặc không đổi cho vật chất đó) chiều rộng/chiều cao trên chế độ xem chia nhỏ là đặt những thứ đó trên chế độ xem riêng lẻ. Đặc biệt, nếu bạn đang làm điều này trong mã, bạn sẽ cần phải sử dụng 2 cuộc gọi riêng biệt để ràng buộcWithVisualFormat, bởi vì nếu không ngôn ngữ định dạng trực quan sẽ tạo ra các ràng buộc giữa các khung nhìn.

Bạn có thể làm tất cả điều này trong IB tốt. Bạn thậm chí có thể đặt mức độ ưu tiên của mỗi chế độ xem trong chế độ xem chia tách, điều này sẽ khiến một hoặc một chế độ xem khác thay đổi kích thước khi cửa sổ thay vì phân phối kích thước bằng nhau.

+0

Thật thú vị khi nghe cách bạn đề xuất làm điều này tất cả trong IB với tính năng AutoLayout được bật .... – Dad

+0

thực sự không khả thi trong 10.7 - điều khiển để đặt giới hạn chiều rộng trên chế độ xem nội dung NSSplitView bị tắt trong Xcode 4.5.2 dưới 10.7 và nếu bạn đặt nó trong Xcode trên 10.8 và sau đó chạy ứng dụng trên 10.7, nó sẽ phá vỡ ràng buộc đó có lợi cho NSAutoresizingMaskLayerConstraint trong 10.7 và do đó không hoạt động. – Dad

4

NSSplitView là một điều kỳ lạ ngay từ đầu và nó sẽ không làm tôi ngạc nhiên nếu nó sẽ sớm biến mất. Sau khi cố gắng để có được NSSplitView làm việc với AutoLayout trong một tháng và chìm từ một cuộc tấn công tuyệt vọng đến một cuộc tấn công khác, cuối cùng tôi đã từ bỏ.

Giải pháp của tôi là không sử dụng NSSplitView với AutoLayout. Vì vậy, hoặc là NSSplitView không có Autolayout hoặc Autolayout mà không có NSSplitView: điều này không phức tạp như âm thanh: chỉ cần đặt ra các bản xem trước của bạn bên cạnh nhau và thêm NSLayoutConstraintsIBOutlets. Hằng số của các ràng buộc này sau đó có thể được thiết lập và thay đổi từ bộ điều khiển trong mã. Với cách tiếp cận đó bạn có thể thiết lập nguồn gốc (offset âm để trượt nó ra khỏi cửa sổ), chiều rộng và quan hệ với các subviews khác - cộng với các ràng buộc animate với animation của view (bao giờ cố gắng animate một NSSplitView?)

Điều duy nhất còn thiếu là kéo chuột trên ngăn, nhưng điều này có thể được triển khai bằng một vài dòng, theo dõi mouseEvents trong "SplitView" tùy chỉnh của bạn.

Có một ví dụ "chia nhỏ" autolayout từ Apple (tiếc là chỉ theo chiều dọc) và tôi đã nhìn thấy ít nhất một dự án mới trên github gần đây. Mặc dù đối với tôi, tôi nghĩ sẽ dễ dàng hơn khi bắt đầu lại với giải pháp tùy chỉnh cho các nhu cầu cụ thể của ứng dụng của tôi, thay vì cố gắng tạo ra thứ gì đó rất phổ biến (do đó làm cho nó quá phức tạp để xử lý).

Chỉnh sửa: Bây giờ tôi đã hoàn thành chế độ chia tách tùy chỉnh tải các bản xem trước của nó từ các ngòi ngách riêng biệt. Không có vấn đề ràng buộc, không có cảnh báo autolayout. So với cả tháng cố gắng làm cho nó hoạt động với NSSplitView, bây giờ tôi đã có một khung nhìn tùy chỉnh hoạt động dựa trên các ràng buộc, dễ dàng sinh động, được tạo ra chỉ trong một buổi tối. Tôi chắc chắn khuyên bạn nên dùng tuyến đường này!

+0

Bạn có thể chia sẻ mã phân tách tùy chỉnh của mình không? –

+1

@ Ben-Uri: Tôi có một dự án nhỏ trong [answer] (http://stackoverflow.com/a/13964486/456851) có thể được sử dụng cho bạn. –

+0

Vô lý - hoạt động giống như AL với 10.8+ – Jay

0

Nhiều như tôi ghét không đồng ý, nhưng câu trả lời của Auco không nên được bỏ phiếu cao nhất. Nó không phải là trong bất kỳ cách nào hữu ích trong việc giải quyết vấn đề với một số lượng công việc đầy đủ. Theo quan điểm của tôi, NSSplitView chỉ là một vấn đề đối với những người không đọc đủ tài liệu.

Giải pháp thực tế cho vấn đề được đề cập ở đây khá đơn giản: Bố cục tự động đã giới thiệu "API ưu tiên giữ" mới trên NSSplitView. Và như các tài liệu nói: Đặt giá trị thấp hơn để ưu tiên giữ của một subview sẽ làm cho anh ta nhiều khả năng để có chiều rộng trước đó. Tất cả điều này có thể được thiết lập trong IB và lập trình mà không có bất kỳ tuyệt vọng nào. Lượng công việc cần thiết: khoảng 20 giây.

+1

Câu trả lời này sẽ hữu ích hơn nếu nó chỉ trả lời câu hỏi, thay vì thể hiện sự khinh miệt như vậy đối với những người trả lời và câu hỏi khác. Tôi sẽ cung cấp cho bạn 1 câu trả lời và -1 cho sự thô lỗ, vì vậy họ hủy bỏ nhau. –

+1

@Jacque: Nếu bạn cũng đã đọc tài liệu, bạn sẽ thấy rằng việc giữ các ưu tiên chỉ hoạt động trên OS X 10.8+. Không cần phải thận trọng với những người khác khi có lẽ họ đang nghĩ về khả năng tương thích ngược và bạn thì không. –

+1

@Jacque: Bạn có thể đúng nếu bạn đang xử lý một bố cục thực sự đơn giản, chẳng hạn như hai textViews dưới dạng các bản xem trước của một chế độ xem splitView. Nhưng ngay sau khi bạn cần xử lý các subviews được sắp xếp phức tạp, việc thiết lập các ưu tiên giữ sẽ không giúp ích gì nhiều: nội dung trong một splitView sử dụng autolayout tạo ra các lỗi autolayout vì nó xung đột với các mặt nạ tự động hóa. Hoạt hình SplitViews là một cơn đau ở mông, bởi vì bạn cần phải tính toán khung, đó là một không-đi khi sử dụng bố trí tự động. Có nhiều vấn đề thực sự hơn bạn có thể giải quyết chỉ bằng cách giữ các ưu tiên. – auco

7

tôi phát hiện ra rằng lỗi này xuất hiện nếu tôi có thanh công cụ trong cửa sổ và kiểm soát xem chia của tôi bằng bất kỳ phương pháp đại biểu này:

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

Giải pháp được tìm thấy trong việc gắn thanh công cụ vào cửa sổ trong cửa sổDidLoad.

+0

Tôi đã gặp vấn đề tương tự với NSTabView, bỏ chọn hộp kiểm 'Hiển thị lúc khởi động' của thanh công cụ và sau đó làm cho nó hiển thị trong 'windowDidLoad' đã loại bỏ các cảnh báo ngu ngốc. Cảm ơn gợi ý. – DarkDust

+0

Trong chế độ xem phân tách dựa trên bố cục tự động với các giới hạn độ rộng tối thiểu/tối đa, tôi có cùng một vấn đề. Loại bỏ tất cả 3 phương thức đại biểu này đã giải quyết nó. –

+2

Rất nhiều thông tin sai lệch về câu hỏi này. Câu trả lời này là đúng hướng, nhưng kinh doanh thanh công cụ là một cá trích đỏ. Vấn đề được ghi lại trong ghi chú phát hành AppKit (https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKitOlderNotes/index.html#10_11SplitView); một số phương thức 'NSSplitViewDelegate' không hoạt động tốt với tính năng tự động trả lời và không được sử dụng. Thay vào đó, thiết lập các ràng buộc thích hợp trên 'NSView' trực tiếp dưới' NSSplitView', và nó sẽ hoạt động tốt mà không cần đăng nhập. – bhaller

3

Đối với bất cứ ai tình cờ vào này trong tương lai và đang tìm kiếm một bước nhảy khởi động vào chế dựa trên NSSplitView thay thế, tôi đã viết một dự án nhỏ ở đây là cố gắng để tái tạo một phần của tính năng NSSplitView 's sử dụng Auto Layout:

https://github.com/jwilling/JWSplitView

Đó là hơi lỗi, nhưng nó có thể là một tham chiếu hữu ích cho bất kỳ ai muốn đi tuyến đường này.

0

Tôi mất một thời gian để có được cảnh báo tự động xóa sạch cảnh báo nhưng tôi đã làm cho nó được xử lý trong IB (một số bản xem và phân tách).

bố trí của tôi trông giống như:

RootView
    | - 1st NSSplitView (3 subviews dọc)
            | ---- UIView (trái)
            | ---- 2nd NSSplitView (trung tâm & 2 subviews ngang)
                      | --- UIView (trên cùng)
                      | --- 3rd NSSplitView (dưới cùng & 3 bản xem trước theo chiều dọc)
                              | --- UIView (trái)
                              | --- UIView (trung tâm)
                              | --- UIView (bên phải)
            | ---- UIView (bên phải)

Vấn đề của tôi là, rằng tôi đã có 19 cảnh báo trong tất cả các cuộc phỏng vấn của tôi nhưng bố cục của tôi trông ổn và làm việc như thế nào. Sau một thời gian tôi tìm thấy nguyên nhân của các cảnh báo của tôi: các ràng buộc của các quan điểm bên ngoài trong phân chia đầu tiên của tôi.

Cả hai chế độ xem (trái và phải) đều có giới hạn chiều rộng với "width> = 200" và chế độ xem trung tâm (splitview 2) không có ràng buộc (vì chiều rộng tối thiểu và chiều rộng tối đa của nó được xử lý bởi các bản phụ của nó) .

Cảnh báo cho tôi thấy rằng autolayout muốn thu nhỏ IB-UI-Layout vì độ rộng tối thiểu được tính nhỏ hơn bố cục của tôi nhưng tôi không muốn thu nhỏ nó trong IB.

Tôi đã thêm một ràng buộc cố định "width = 200" vào cả hai chế độ xem phụ bên ngoài của chế độ xem phân tách đầu tiên và được chọn "xóa tại thời gian xây dựng".

Bố cục của tôi không có cảnh báo và mọi thứ hoạt động như thế nào.

Kết luận của tôi:

Tôi nghĩ vấn đề với autolayout và splitviews là autolayout không thể xử lý chiều rộng hạn chế của subviews. Lý do chúng tôi muốn sử dụng phân tách là, chúng tôi muốn chiều rộng động của các chế độ xem và chúng tôi muốn nó theo cả hai hướng, thu nhỏ và mở rộng.

Vì vậy, không có chiều rộng < = xxx & & chiều rộng> = xxx. Autolayout chỉ có thể xử lý một trong số đó và chúng tôi nhận được cảnh báo trong IB. Bạn có thể khắc phục vấn đề này với một ràng buộc tạm thời trong IB sẽ bị xóa trước khi chạy.

Tôi hy vọng nó làm cho cảm giác những gì tôi đã viết nhưng nó làm việc tốt trong dự án của tôi.

PS: Tôi không thể tìm thấy bất kỳ giải pháp đến ngày hôm nay nơi tôi tìm thấy chủ đề này .. vì vậy tôi đoán bài viết của mình cảm hứng cho tôi :-)

0

tôi sử dụng lớp này như một cách giải quyết, nó không hoàn hảo (nói lắp subviews một chút) nhưng nó đã cấm tôi. Tôi sử dụng lớp này làm lớp tùy chỉnh bên trong mỗi ngăn xem chia tách.

@interface FBSplitPaneView : NSView 

@end 

@implementation FBSplitPaneView 

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

@end