NSSplitView and autolayout

2019-03-11 04:03发布

How should I use auto layout constrains inside NSSplitView subview?

My NSSplitView subview has 3 subview: topPane, tableContainer and bottomPane and I set the constrains like this:

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

And got this in console:

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

I think <NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]> causes this, but I can't reset autoresizing mask, because NSSplitView sets it.

What is best way to use auto layout inside split view? And is there any way to handle min/max size of split view subview with auto layout without NSSplitViewDelegate?

9条回答
ゆ 、 Hurt°
2楼-- · 2019-03-11 04:08

For anyone who stumbles onto this in the future and is looking for a jump-start into constraint-based NSSplitView replacements, I wrote a small project here that attempts to recreate a portion of NSSplitView's features using Auto Layout:

https://github.com/jwilling/JWSplitView

It's somewhat buggy, but it could be a useful reference to anyone wanting to go this route.

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-03-11 04:09

10.8 fixed that problem, see its release notes.

Here is my solution for 10.7 (a custom split view): https://github.com/benuri/HASplitView.git

查看更多
冷血范
4楼-- · 2019-03-11 04:13

NSSplitView has been a strange thing since the beginning and it would not surprise me if it'll be gone soon. After trying to get NSSplitView working with AutoLayout for a month now and sinking from one despair attack to another, I finally gave up.

My solution is to not use NSSplitView with AutoLayout at all. So either NSSplitView without Autolayout or Autolayout without NSSplitView: this isn't as complicated as it sounds: just lay out your subviews next to each other and add NSLayoutConstraints as IBOutlets. The constants of these constraints can then be set and changed from the controller in code. With that approach you can set the origin (negative offset to slide it out of the window), the width and the relations to other subviews - plus it's really easy to animate constraints with the view's animator (ever tried to animate a NSSplitView?)

The only thing missing is the mouse drag on the dividers, but this can be implemented with a couple of lines, tracking mouseEvents in your custom "SplitView".

There's an autolayout "splitview" example from Apple (unfortunately only vertical) and I've seen at least one new project on github lately. Though for me, I thought it'd be easier to start over with my custom solution for my app's specific needs, rather than trying to create something very universal (thus making it too complex to handle).

Edit: I now completed my custom splitView that loads its subviews from separate nibs. No constraint issues, no autolayout warnings. Compared to the whole month of trying to get it work with NSSplitView, I have now a working custom splitView based on constraints, easily animatable, created in only one evening. I definitely recommend taking this route!

查看更多
趁早两清
5楼-- · 2019-03-11 04:15

I found out that this error appears if I have toolbar in my window and control split view by any of this delegate methods:

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

Solution was found in attaching toolbar to window in windowDidLoad.

查看更多
戒情不戒烟
6楼-- · 2019-03-11 04:17

I load all by a nib file and setTranslatesAutoresizingMaskIntoConstraints:NO afterwards.

So maybe you should first add by [mySplitView addSubview:myView]; your views and disable afterwards the translation of the autosizing mask to constraints and after this you add your contraint to myView.

EDIT:

Ok it seems I missunderstand the myView. You have to add the constraint to the subviews and not to the splitview.

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

You don't have to add edge constraints (the "|" in "V:|[topPane(34)]") because the subviews in NSSplitView are already autoresizing.

This lead to this e.g. for the topPane constraint:

Screenshout

NOTE: ignore the subview content, they are just placeholders

查看更多
太酷不给撩
7楼-- · 2019-03-11 04:23

You do not want to disable translatesAutoresizingMaskIntoConstraints at all. You shouldn't mess with system views constraints. NSSplitView handles the sizing for the individual views itself and you are essentially trying to rip it's control away. Not to mention, you forgot to account for the splitter.

The correct way to set a minimum or maximum (or constant for that matter) width/height on a splitview is to set those things on the views individually. In particular, if you are doing this in code you will need to use 2 separate calls to constraintsWithVisualFormat, because otherwise the visual format language will create constraints between the views.

You can do all of this in IB just fine. You can even set the priority of each view in the split view, which will cause one or the other view to resize when the window does rather than distributing the resize equally.

查看更多
登录 后发表回答