如何设置NSSplitView的位置? setPosition:ofDividerAtIndex:不起作用,我不确定如何进行临时约束

时间:2016-01-03 07:57:30

标签: macos cocoa autolayout nssplitview

我有一个垂直NSSplitView,左侧是NSScrollView(NSOutlineView,源列表,没有标题视图),右侧是WebView。所有视图都有NSZeroRect的初始帧。 NSSplitView,NSScrollView和WebView的自动调整遮罩处于关闭状态,NSSplitView用于使用自动布局填充窗口。我似乎无法强制NSSplitView分隔符位于给定位置;

[sv setPosition:250 ofDividerAtIndex:0];

简单地拒绝生效。虽然我的用例是初始位置,但我最终还是需要一个可以随时使用的解决方案,因为我没有使用nib / xib文件。

无论是否有上述setPosition:调用,WebView都会获得NSSplitView的整个宽度。如果我将NSScrollView的初始帧设置为NSMakeRect(0, 0, 250, 0)它可以工作。当然,这只是初始帧,这是不够好的(并且可以抵抗UI布局的变化)......我发现的所有东西早于自动布局,并且说你应该直接操作帧;由于这是自动布局,我怀疑这是个好主意......

但它更奇怪:如果我将分隔符样式设置为NSSplitViewDividerStyleThin,即使NSMakeRect()被忽略,NSScrollView也会被赋予NSSplitView的全宽,无论如何。

那为什么我不能设置NSSplitView的位置?

是因为位置是由自动布局决定的吗?在这种情况下,如何设置约束以强制左视图的宽度为给定宽度,让布局管理器运行以应用该约束,然后立即删除约束?我尝试覆盖NSSplitView的layoutupdateConstraints来做,但是自动布局并不像我那样,当我再次尝试移动分隔线时没有效果并且崩溃!

或者我真的应该直接操纵NSSplitView子视图的框架,尽管Auto Layout最佳实践是什么?

是的,我已经在多次以及其他一些页面上阅读了每个类似的问题;它的所有建议要么不起作用,要么说setPosition:应该神奇地工作。

这是OS X 10.11,但我需要一个可以追溯到10.7的解决方案。

以下Swift 2程序快速演示了我的意思。您可以使用appLaunched()中的各种代码行来尝试各种效果。无论出于何种原因,我上面提到的奇怪的事情(左边的视图占据了分隔线样式为薄的所有空间)不会发生在这里。那是我对此感到困惑的其他事情......

感谢。

// 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()

2 个答案:

答案 0 :(得分:3)

我遇到了同样的问题,我设法通过使用相同的参数调用setPosition:ofDividerAtIndex:两次来解决它。也许它也适合你。

答案 1 :(得分:0)

对我有用的是,在调用setPosition方法之后设置嵌套视图的框架:

let splitWidth = 600

splitViewController.splitView.setPosition(splitWidth, ofDividerAt: 0)

if let frame = splitViewController.splitViewItems.first?.viewController.view.frame {
    splitViewController.splitViewItems.first?.viewController.view.setFrameSize(NSSize(width: splitWidth, height: frame.height))
}

此代码基于使用NSSplitViewController,因此可能不适用于原始问题中描述的用例。