使用 SwiftUI 定义 macOS 窗口大小

wig*_*ing 16 macos swift 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

ContentView 定义如下:

// --- ContentView.swift ---

import SwiftUI

struct ContentView : View {
    var body: some View {
        VStack {
            Spacer()
            Text("Top Text")
            Spacer()
            Text("Bottom Text")
            Spacer()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

kon*_*iki 22

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

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

既然那不碍事,你的窗口如此狭窄的原因如下:

使用 SwiftUI,并非所有视图都是平等的。例如: Text() 是谦虚的。它只会根据需要占用尽可能多的空间。而其他视图,例如 Spacer(),会像它们的父母提供的一样扩展(我称之为贪婪)。

在您的情况下,您有一个 VStack,其中包含 Spacer()。这意味着 VStack 填充会扩展以填充其父级提供的高度。在这种情况下,来自委托的 300 pt(或存储在 UserDefaults 中的任何内容)。

另一方面,由于您在 HStack 中没有任何 Spacer(),因此 ContentView 只会水平扩展到它需要的位置。也就是说,与最宽的 Text() 视图一样宽。如果您HStack { Spacer() }在 VStack 内添加,您的内容视图扩展以占据委托中指定的 480 pt(或存储在 UserDefaults 中的任何内容)。无需设置框架()。

另一种方法(为 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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我写了一篇关于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)
}
Run Code Online (Sandbox Code Playgroud)

更新(macOS Catalina - Beta 3)

由于 Beta3,新项目的初始 ContentView,使用 maxWidth 和 maxHeight。一个聪明的选择。

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


Moj*_*ini 16

只需给出一个大小content(或使其自定大小)并告诉窗口组将其大小限制为其内容:

@main
struct MySizingApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .frame(minWidth: 350, minHeight: 350) // <- 1. Size here
        }
        .windowResizability(.contentSize) // <- 2. Add the restriction here
    }
}
Run Code Online (Sandbox Code Playgroud)


Lor*_*bis 8

我就是这样做的。它有一个启动大小和可调整大小。

struct windowSize {
// changes let to static - read comments
static minWidth : CGFloat = 100
static minHeight : CGFloat = 200
static maxWidth : CGFloat = 200
static 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)
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 8

斯威夫特用户界面

在我的例子中,您可以轻松地在主结构中使用(编译器指令),当我正在开发多平台应用程序(iPhone,iPad,mac)时,我用它来检测哪个屏幕应用程序正在运行

import SwiftUI

@main
struct DDStoreApp: App {
    var body: some Scene {
        WindowGroup {
            // use compiler directives #if to detect mac version or ios version
            #if os(macOS)
            // use min wi & he to make the start screen 800 & 1000 and make max wi & he to infinity to make screen expandable when user stretch the screen 
            ContentView().frame(minWidth: 800, maxWidth: .infinity, minHeight: 1000, maxHeight: .infinity, alignment: .center)
            #else
            ContentView()
            #endif
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 对 macOS 没有影响 (4认同)