2

I want to implement a Mail-like NSSplitView so that, when divider 0 is dragged, it pushes divider 1 (compressing subview 2 while width of subview 1 is fixed).

-----------------
|   |   |       |
| 0 | 1 |   2   |
|   |   |       |
|   |   |       |
-----------------

So far, I have no luck doing so successfully with a single NSSplitView with auto layout.

I tried checking the problem with Instruments. It looks like, after certain point (#783 in the screenshot), the constraint doesn't have high enough priority to keep pushing.

enter image description here

Have you successfully a NSSplitView with similar configuration before?

Or, in general, some advice to further debug this issue?

Some people suggest using nested NSSplitView to implement this behavior. But I wanna check how this can be done using a single NSSplitView. (Looks like "Notes" app is done with a single NSSplitView)

Thanks loads

Bill

My test code is here

billibala
  • 321
  • 4
  • 14
  • Have you looked at the ``NSSplitViewDelegate Protocol``? It's possible that you won't be able to get the behaviour you're after solely through setting priorities in Interface Builder. The protocol gives some further opportunities for customising the size of the subviews and the position of the splits. – Paul Patterson Nov 04 '14 at 00:17
  • Agree. Battled with auto layout in the past few days. I am able to solve some of the problem but there's one thing not that right... – billibala Nov 05 '14 at 07:48

2 Answers2

2

You don’t need autolayout for this. NSSplitView has the concept of “holding priorities” for its subviews. You should set the holding priority of view 2 to be smaller than 0 and 1.

Jaanus
  • 17,688
  • 15
  • 65
  • 110
1

I wanna share the investigation I did in the past few days. I am able to get NSSplitView behaves the way I want partially. It's not a complete solution yet. But, hopefully, someone can help me answer the part I can't.

"Notes" app possibly uses a single NSSplitView.

enter image description here

The above screenshot shows "Notes" app running in Xcode 6 Veiw Debugger mode.

It's a subclass of NSSplitView called MainSplitView.

To study how "Notes" app's split view behave the way I want when dividers are resized, I open it with "Cocoa Layout" instrument from Xcode Instruments and study the constraint events when I move divider 0 rightward.

enter image description here

Studying the constraint events and compare it with the log generated running the original version of my sample app...

enter image description here

I found that the main difference is... the constraint between the rightmost subview with the split view's left edge has "low" priority in "Notes" app. A similar constraint has "required" priority in my sample app.

So, I tried implement my own MainSplitView. Override the "addConstraints:" method so that a lower priority is set to the constraint.

- (void)addConstraints:(NSArray *)constraints {
    NSLog(@"adding constraints: %@", constraints);
    NSLayoutConstraint * theConstraint = constraints.firstObject;
    if ( theConstraint.firstItem == self.subviews.lastObject && theConstraint.secondItem == self ) {
        theConstraint.priority = NSLayoutPriorityDefaultLow;
        [super addConstraints:@[theConstraint]];
    } else {
        [super addConstraints:constraints];
    }
    NSLog(@"========== constraings affecting layout ===========");
    for (NSView * theView in self.subviews) {
        NSLog(@"view: %@\n%@", theView, [theView constraintsAffectingLayoutForOrientation:NSLayoutConstraintOrientationHorizontal]);
    }
}

You can find the code here.

After the change, my sample app, when I drag divider 0, it will pushes the middle subview rightward, maintains its width, compressing the rightmost view.

But now... I run into another problem...

enter image description here

Every time I move divider 0, it can only moves, at most, to the starting position of divider 1.

Is this another constraint configuration issue? Or, some other initial behavior of NSSplitView that we need to customize?

Any help/advice?

Thanks Bill

billibala
  • 321
  • 4
  • 14