使用SwiftUI定义macOS窗口大小

使用SwiftUI定义macOS窗口大小,swift,macos,swiftui,Swift,Macos,Swiftui,我正在使用SwiftUI开发一个新的macOS应用程序,但不知道如何定义窗口大小。在AppDelegate中,窗口大小的定义如下所示: // --- AppDelegate.swift --- import Cocoa import SwiftUI @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { var window: NSWindow! func applicationDi

我正在使用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应用程序的窗口大小?

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

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

现在,这是不可能的,你的窗户如此狭窄的原因如下:

使用SwiftUI时,并非所有视图都是相同的。例如:Text()是谦逊的。它将只占用所需的空间。而其他视图,如Spacer(),将扩展到它们的父视图提供的范围(我称它们为贪婪视图)

在本例中,您有一个VStack,其中包含间隔符()。这意味着VStack填充将展开以填充其父级提供的高度。在本例中,来自委托的300 pt(或存储在UserDefaults中的任何内容)

另一方面,由于HStack中没有任何间隔符(),ContentView将仅水平扩展到它需要的位置。也就是说,与最宽的Text()视图一样宽。如果在VStack中添加
HStack{Spacer()}
,则内容视图将展开以占用委托中指定的480 pt(或存储在UserDefaults中的任何内容)。无需设置帧()

另一种方法(为ContentView指定一个框架)基本上是告诉您的ContentView是480x300,不管怎样。事实上,如果您这样做,您将无法调整窗口的大小

所以现在你知道了,我想这很清楚。。。但是,这里有一些东西对你非常有用:

还有另一个贪婪的视图可以帮助您调试窗口大小:GeometryReader。这一观点将总是采取尽可能多的提供。运行此示例,您将确切知道应用程序启动时提供了多少空间:

struct ContentView:View{
var body:一些观点{
GeometryReader{中的几何体
VStack{
文本(“\(geometry.size.width)x\(geometry.size.height)”)
}.框架(宽度:几何体.尺寸.宽度,高度:几何体.尺寸.高度)
}
}
}
我写了一篇关于GeometryReader的广泛文章,我建议你去看看:

顺便说一下,我的AppDelegate如下所示:

func applicationdFinishLaunching(\u通知:通知){
//在此处插入代码以初始化应用程序
window=NSWindow(
contentRect:NSRect(x:0,y:0,宽度:480,高度:300),
样式掩码:[.标题、.closable、.Minimable、.Resize、.fullSizeContentView],
备份:。已缓冲,延迟:false)
window.center()
window.setFrameAutosaveName(“主窗口”)
window.contentView=NSHostingView(rootView:contentView())
车窗。MakeKeyandDerfront(无)
}
更新(macOS Catalina-Beta 3) 因为新项目的初始ContentView Beta3使用maxWidth和maxHeight。一个聪明的选择

struct ContentView:View{
var body:一些观点{
文本(“你好,世界”)
.frame(maxWidth:无穷大,maxHeight:无穷大)
}
}

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

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)
  }
}

我只是想帮点忙,但可能不是因为我(还)没有做过
macOS
app。想想“固有大小。我想这就是为什么它看起来“大致相当于两个文本标签的大小”。除非添加修改器,否则它应该是这样。如果添加一个-
.frame(宽度:480,高度:300),会怎么样第二件事-不要使用<代码> AppReaveT//Cuff>来定义这样的事情。在iOS中,你现在想要的是<代码> StEdEdGeaveT/<代码>,因为对于iPad来说,你终于有了多线程。我猜你现在需要考虑整个屏幕是一个“画布”,用于你的应用程序的单一实例。所以在你的例子中,每一个“场景”或“您希望的实例“需要设置为480x300,最佳位置IMHO不在场景级别-但您没有提供该上下文-而是在
视图
级别。@dfd您将在哪里声明
.frame
?在VStack上?考虑把你的建议作为回答而不是评论。我真的感觉不到这是一个答案,因为-自从我和Windows应用程序一起工作以来…哇,1995年-我真的不知道
AppKit
。所以让我尽我所能。。。(1) 记住,这仍然是beta 2。事情会改变的。(2) 试试看。修改器的位置和顺序很重要。所以,是的,我会尝试第二次(!)使用
堆栈,然后第一次使用
ContentView。如果这两种方法都有效,我建议你提交你自己的答案——没问题——我当然会投赞成票。为什么Xcode中的默认macOS项目在使用SwiftUI时会定义AppDelegate中的窗口大小?正如您在回答中所示,显然您是使用内容视图框架定义窗口大小的。您的AppDelegate代码是什么样子的?您是否从AppDelegate中删除了NSWindow?好的,我刚刚找到了答案。有几个因素。我正在更新我的答案。给我几分钟。好的,我更新了我的答案。我希望现在已经清楚了。如果您需要进一步的澄清,请告诉我。谢谢您的深入回答。