I have a vertical NSSplitView with a NSScrollView(NSOutlineView, source list, no header view) on the left and a WebView on the right. All the views have initial frames of NSZeroRect
. Autoresizing masks are off for the NSSplitView, NSScrollView, and WebView, and the NSSplitView is made to fill the window with Auto Layout. I cannot seem to force the NSSplitView divider to be at a given position;
[sv setPosition:250 ofDividerAtIndex:0];
simply refuses to take effect. Though my use case is for an initial position, I will eventually need a solution that works at any time, since I'm not using a nib/xib file for this.
With or without the setPosition:
call above, the WebView is given the entire width of the NSSplitView. If I set the initial frame of the NSScrollView to NSMakeRect(0, 0, 250, 0)
it works. Of course, that's only for the initial frame, which isn't good enough (and is resistant to UI layout changes)... Everything I've found predates Auto Layout, and says you should just manipulate frames directly; since this is Auto Layout, I doubt that's a good idea...
But it gets weirder: if I set the divider style to NSSplitViewDividerStyleThin
, even the NSMakeRect()
is ignored and the NSScrollView is given the full width of the NSSplitView, no matter what.
So why can't I set the position of the NSSplitView?
Is it because the position is determined by Auto Layout? In that case, how do I set up a constraint to force the width of the left view to be a given width, let the layout manager run to apply that constraint, and then immediately remove the constraint? I tried overriding NSSplitView's layout
and updateConstraints
to do it, but Auto Layout did not really like that I did, having no effect AND crashing when I try to move the dividers again!
Or am I really supposed to manipulate the frame rects of NSSplitView subviews directly, despite what Auto Layout best practices are?
And yes, I have read every similar question here multiple times, as well as on a few other pages; all its suggestions either don't work or say setPosition:
should magically work.
This is OS X 10.11, but I need a solution that goes back to 10.7.
The following Swift 2 program quickly demonstrates what I mean. You can play with the various lines of code in appLaunched()
to try out the various effects. For whatever reason, the weird thing I noted above (the view on the left taking all the space if the divider style is Thin) doesn't happen here, though. That's something else I'm confused about...
Thanks.
// 3 january 2016
// scratch program 17 august 2015
import Cocoa
import WebKit
var keepAliveMainwin: NSWindow? = nil
func appLaunched() {
let mainwin = NSWindow(
contentRect: NSMakeRect(0, 0, 320, 240),
styleMask: (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask),
backing: NSBackingStoreType.Buffered,
`defer`: true)
let contentView = mainwin.contentView!
let splitView = NSSplitView(frame: NSZeroRect)
splitView.dividerStyle = NSSplitViewDividerStyle.Thin
splitView.vertical = true
splitView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(splitView)
let box1 = NSScrollView(frame: NSZeroRect)
let ov = NSOutlineView(frame: NSZeroRect)
ov.headerView = nil
ov.selectionHighlightStyle = NSTableViewSelectionHighlightStyle.SourceList
box1.documentView = ov
box1.translatesAutoresizingMaskIntoConstraints = false
splitView.addSubview(box1)
let box2 = WebView(frame: NSZeroRect)
box2.translatesAutoresizingMaskIntoConstraints = false
splitView.addSubview(box2)
let views: [String: NSView] = [
"splitView": splitView,
]
addConstraint(contentView, "H:|-[splitView]-|", views)
addConstraint(contentView, "V:|-[splitView]-|", views)
splitView.setPosition(50, ofDividerAtIndex: 0)
mainwin.cascadeTopLeftFromPoint(NSMakePoint(20, 20))
mainwin.makeKeyAndOrderFront(mainwin)
keepAliveMainwin = mainwin
}
func addConstraint(view: NSView, _ constraint: String, _ views: [String: NSView]) {
let constraints = NSLayoutConstraint.constraintsWithVisualFormat(
constraint,
options: [],
metrics: nil,
views: views)
view.addConstraints(constraints)
}
class appDelegate : NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(note: NSNotification) {
appLaunched()
}
func applicationShouldTerminateAfterLastWindowClosed(app: NSApplication) -> Bool {
return true
}
}
func main() {
let app = NSApplication.sharedApplication()
app.setActivationPolicy(NSApplicationActivationPolicy.Regular)
// NSApplication.delegate is weak; if we don't use the temporary variable, the delegate will die before it's used
let delegate = appDelegate()
app.delegate = delegate
app.run()
}
main()