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条回答
一夜七次
2楼-- · 2019-03-11 04:23

As much as I hate to disagree, but Auco's answer should't be voted highest. It is not in any way helpful in solving the problem with an adequate amount of work. In my opinion the NSSplitView was only ever a problem to those who didn't read the documentation well enough.

The actual solution to the problem mentioned here is fairly simple: Auto Layout introduced the new "Holding Priorities API" on NSSplitView. And as the documentation says: Setting lower values to the holding priority of a subview will make him more likely to take width earlier. All of this can be set in IB and programmatically without any despair. The amount of work needed: 20 seconds approx.

查看更多
贼婆χ
3楼-- · 2019-03-11 04:25

I used this class as a workaround, it's not perfect (the subviews stutter a bit) but it unblocked me. I use this class as the custom class inside each split view pane.

@interface FBSplitPaneView : NSView

@end

@implementation FBSplitPaneView

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

@end
查看更多
放荡不羁爱自由
4楼-- · 2019-03-11 04:30

It took me some time to get my autolayout clean of warnings but I did get it handled in IB (several splitviews and subviews).

My layout looks like:

RootView
  |--1st NSSplitView (3 vertical subviews)
      |----UIView (left)
      |----2nd NSSplitView (center & 2 horizontal subviews)
           |---UIView (top)
           |---3rd NSSplitView (bottom & 3 vertical subviews)
               |---UIView (left)
               |---UIView (center)
               |---UIView (right)
      |----UIView (right)

My problem was, that I had 19 Warnings in all my subviews but my layout looked fine and worked how it should be. After a while I found the cause of my warnings: the constraints of the outer views in my first splitview.

Both views (left and right) had a width-constraint with "width >= 200" and the center view (2nd splitview) had no constraints (because its min-width and max-width where handled by its subviews).

The warnings showed me that autolayout wants to shrink my IB-UI-Layout because the calculated min-widths where smaller than my layout but I didn´t want to shrink it in IB.

I added a fixed constraint "width = 200" to both of the outer subviews of my first splitview and checked "remove at build time".

Now my layout is free of warnings and everything works how it should be.

My conclusion:

I think the problem with autolayout and splitviews is that autolayout can not handle the width-constraints of the subviews. The reason we want to use splitviews is, that we want dynamic width of the views and we want it in both directions, shrink and expans.

So there is no width <= xxx && width >= xxx . Autolayout can only handle one of it and we get warnings in IB. You can fix this problem with a temporary constraint in IB which will removed before runtime.

I hope it makes sense what I wrote but it worked fine in my project.

PS: I could not found any solution until today where I found this thread.. so I guess your posts inspired me :-)

查看更多
登录 后发表回答