使用SwiftUI定义macOS窗口大小

时间:2019-07-02 17:54:22

标签: swift macos swiftui

我正在使用SwiftUI开发新的macOS应用程序,但无法弄清楚如何定义窗口大小。在AppDelegate中,窗口大小定义如下:

// --- AppDelegate.swift ---

import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    var window: NSWindow!


    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Insert code here to initialize your application
        window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        window.center()
        window.setFrameAutosaveName("Main Window")

        window.contentView = NSHostingView(rootView: ContentView())

        window.makeKeyAndOrderFront(nil)
    }
}

ContentView的定义如下:

// --- ContentView.swift ---

import SwiftUI

struct ContentView : View {
    var body: some View {
        VStack {
            Spacer()
            Text("Top Text")
            Spacer()
            Text("Bottom Text")
            Spacer()
        }
    }
}

当我构建并运行该应用程序时,会出现一个窗口,但它的大小不正确。它显示为大约两个文本标签的大小,而不是AppDelegate中定义的480x300大小。

使用SwiftUI时,我应该如何为Mac应用程序定义窗口大小?

2 个答案:

答案 0 :(得分:3)

我是这样做的。它具有启动大小并且可调整大小。

struct windowSize {
let minWidth : CGFloat = 100
let minHeight : CGFloat = 200
let maxWidth : CGFloat = 200
let maxHeight : CGFloat = 250
}

struct ContentView : View {
  var body: some View {
    Group() {
        VStack {
            Text("Hot Stuff")
            .border(Color.red, width: 1)
            Text("Hot Chocolate")
            .border(Color.red, width: 1)
        }
    }
    .frame(minWidth: windowSize().minWidth, minHeight: windowSize().minHeight)
    .frame(maxWidth: windowSize().maxWidth, maxHeight: windowSize().maxHeight)
    .border(Color.blue, width: 1)
  }
}

答案 1 :(得分:1)

有时,这种行为可能会令人困惑。这是因为一旦至少运行一次应用程序,然后再手动调整窗口大小和位置,则委托中指定的大小将不再重要。

应用程序会记住用户何时调整窗口大小,并使用键“ NSWindow Frame Main Window” 下的UserDefaults中存储的信息。如果您想重置它,则需要使用默认值命令将其清除。

现在,这已经不合时宜了,您的窗口如此狭窄的原因如下:

使用SwiftUI时,并非所有视图都创建相同。例如:Text()很谦虚。它只会占用所需的空间。而诸如Spacer()之类的其他视图将扩大其父母提供的范围(我称它们为贪婪)。

在您的情况下,您有一个带Stackr()的VStack。这意味着VStack填充将扩展为填充其父级提供的高度。在这种情况下,代表需要300点(或存储在UserDefaults中的任何内容)。

另一方面,由于HStack中没有任何Spacer(),因此ContentView将仅水平扩展至所需的水平。也就是说,与最宽的Text()视图一样宽。如果在VStack中添加HStack { Spacer() },则内容视图 将扩展为占据委托中指定的480 pt(或存储在UserDefaults中的任何内容)。无需设置frame()。

另一种方法(为ContentView指定框架)基本上是告诉ContentView不管是什么,都为480x300。实际上,如果这样做,将无法调整窗口大小!

所以现在您知道了,我认为这很清楚...但是,这对您可能非常有用:

还有另一个贪婪的视图可以帮助您调试窗口大小:GeometryReader。此视图将始终采用所提供的视图。运行此示例,您将确切知道在应用启动时提供了多少空间:

struct ContentView : View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("\(geometry.size.width) x \(geometry.size.height)")
            }.frame(width: geometry.size.width, height: geometry.size.height)
        }
    }
}

我写了一篇有关 GeometryReader 的文章,我建议您查看一下:https://swiftui-lab.com/geometryreader-to-the-rescue/

顺便说一句,我的 AppDelegate 看起来像这样:

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Insert code here to initialize your application
    window = NSWindow(
        contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
        styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
        backing: .buffered, defer: false)
    window.center()
    window.setFrameAutosaveName("Main Window")
    window.contentView = NSHostingView(rootView: ContentView())
    window.makeKeyAndOrderFront(nil)
}

更新(macOS Catalina-Beta 3)

从Beta3开始,新项目的初始ContentView使用maxWidth和maxHeight。切肉刀的替代品。

struct ContentView : View {
    var body: some View {
        Text("Hello World")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}