【问题标题】:How do I size an NSWindow with auto-layout?如何使用自动布局调整 NSWindow 的大小?
【发布时间】:2020-04-18 23:07:51
【问题描述】:

一直在尝试 Xcode 为基于 macOS 的文档项目创建的 SwiftUI 默认项目代码。我将窗口创建代码从NSDocument 子类移动到新的NSWindowController 子类。开始是这样的:

init() {
    let content = ContentView()
    let windowSize = NSRect(x: 0, y: 0, width: Constants.defaultWidth, height: Constants.defaultHeight)
    let window = NSWindow(contentRect: windowSize, styleMask: Constants.windowStyle, backing: .buffered, defer: false)
    window.contentView = NSHostingView(rootView: content)
    super.init(window: window)

    // Other setup.
    window.center()
    window.delegate = self
}

现在我想尝试在不指定矩形的情况下创建窗口。有一个初始化器,它使用NSViewController 作为基础:

init() {
    let content = ContentView()
    let controller = NSHostingController(rootView: content)
    let window = NSWindow(contentViewController: controller)
    //window.contentMinSize = NSSize(width: Constants.defaultWidth, height: Constants.defaultHeight)
    window.styleMask.formUnion(.fullSizeContentView)
    super.init(window: window)

    // Other setup.
    //window.center()
    window.delegate = self
}

ContentView 只是 Xcode 的默认值,只有一个“Hello World!”文本块。它似乎没有固有大小,因此窗口缩小到零。现在被注释掉的 contentMinSize 属性并没有修复它。然后我仔细阅读了初始化程序的文档,并决定尝试使用自动布局。

init() {
    // Create and size content.
    let content = ContentView()
    let controller = NSHostingController(rootView: content)
    let guide = NSLayoutGuide()
    controller.view.addLayoutGuide(guide)
    guide.widthAnchor.constraint(greaterThanOrEqualToConstant: CGFloat(Constants.defaultWidth)).isActive = true
    guide.heightAnchor.constraint(greaterThanOrEqualToConstant: CGFloat(Constants.defaultHeight)).isActive = true
    controller.view.translatesAutoresizingMaskIntoConstraints = false
    //controller.view.autoresizesSubviews = false

    let window = NSWindow(contentViewController: controller)
    window.styleMask.formUnion(.fullSizeContentView)
    super.init(window: window)

    // Other setup.
    //window.center()
    window.delegate = self
}

但我仍然有一个消失的窗口。 (对autoresizesSubviews 的注释更改并没有帮助。)然后我注意到那里有一个窗口,但宽度为一个像素,高度约为两个标题栏。但是,当我尝试调整它的大小时,窗口变得可见,跳转到文本块所需的最小大小。触摸后,我无法将窗口缩小到显示文本块所需的下方。但是,最小尺寸仍然小于我的默认宽度和高度,因此这些设置将被忽略。

那么,NSWindow.init(contentViewController:) 想要使用自动布局如何控制窗口的大小?

(嗯,当我输入这个查询时,我不确定我对guide 所做的设置是否连接到controller.view。也许我需要先确保这一点。)

【问题讨论】:

  • 你尝试过利用 NSHostingView 的fittingSize 属性吗?

标签: cocoa autolayout nswindow


【解决方案1】:

关于使用controller.view 而不是新的NSLayoutGuide 对象的最后怀疑似乎有效。

init() {
    // Create and size content.
    let content = ContentView()
    let controller = NSHostingController(rootView: content)
    controller.view.autoresizesSubviews = false
    controller.view.widthAnchor.constraint(greaterThanOrEqualToConstant: CGFloat(Constants.defaultWidth)).isActive = true
    controller.view.heightAnchor.constraint(greaterThanOrEqualToConstant: CGFloat(Constants.defaultHeight)).isActive = true

    let window = NSWindow(contentViewController: controller)
    window.styleMask.formUnion(.fullSizeContentView)
    super.init(window: window)

    window.delegate = self
}

但这只是调整大小;我无法选择窗口在屏幕上的位置。

【讨论】:

    【解决方案2】:

    如果窗口大小在两个方向上都不是动态的(例如将窗口添加到工作表中),请尝试在一个或两个方向上将 fixedSized 视图修饰符添加到您的 SwiftUI 视图中。然后,视图将保持其内容的理想大小,并且窗口应该在外观上尊重该大小。

    我遇到了类似的问题,似乎每当我直接将NSHostingController 添加为NSWindowController 的内容时,与内在尺寸相关的事情开始变得有点古怪。根据视图检查器的说法,SwiftUI 视图的大小实际上是正确的,但宿主控制器的 NSView 本身不是(其中,afaik 看起来像一个错误。我在 NSHostingController 或 UIHostingController 的其他用法中没有看到这种行为......) .

    最后,虽然我没有对此进行太多实验,但在 NSWindowControllerNSHostingController 之间使用中间的 NSViewController 似乎可行。

    【讨论】: