NSWindow contentView 未覆盖完整 window 大小 - macOS 和 SwiftUI

NSWindow contentView not cover full window size - macOS & SwiftUI

我正在使用 SwiftUI 启动一个新的 macOS 应用程序,但我遇到了一个大问题。 该应用程序需要全尺寸 contentView(在 titleBar 下方),但我无法完成。在使用 Storyboards 的新项目上工作正常,但使用 SwiftUI 则不行。

我的代码:

结果:

它应该是这样的:

有什么想法吗? 谢谢!

安全区域不会延伸到透明标题栏下方。您可以使用 edgesIgnoringSafeArea 告诉您的内容视图边缘忽略安全区域。类似于您的示例的内容:

struct ContentView: View {
  var body: some View {
    HStack(spacing: 0) {
      Text("Hello, World!")
        .frame(maxWidth: 200, maxHeight: .infinity)
        .background(Color.red)
      Text("Hello, World!")
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.black)
    }.edgesIgnoringSafeArea(.all)
  }
}

更新: 如果你想使用 NavigationView,你还必须在其内容中添加 edgesIgnoringSafeArea

struct ContentView: View {
  var body: some View {
    NavigationView {
      Text("Hello, World!")
        .frame(maxWidth: 200, maxHeight: .infinity)
        .background(Color.red)
        .edgesIgnoringSafeArea(.all)

      Text("Hello, World!")
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.black)
        .edgesIgnoringSafeArea(.all)

    }.edgesIgnoringSafeArea(.all)
  }
}

不幸的是,这最初会显示一个标题栏,显然直到您强制完全 window 重绘。一旦将 window 移动到不同的显示或隐藏并再次显示,标题栏就会消失。所以,我猜这会在某个时候得到解决。

现在,您可以通过添加

以编程方式强制隐藏和显示
DispatchQueue.main.async {
  self.window.orderOut(nil)
  self.window.makeKeyAndOrderFront(nil)
}

window.makeKeyAndOrderFront(nil) 之后 applicationDidFinishLaunching。但是,它会添加一个非常短的动画。如果它困扰你,你可以用 NSWindow.animationBehavior 或类似的东西把它关掉。

更新 2:显然,如果您删除初始的 window.makeKeyAndOrderFront(nil) 并将其替换为上面的调度 queue 逻辑,它将不会设置动画。所以最后你会得到

func applicationDidFinishLaunching(_ aNotification: Notification) {
  let contentView = ContentView()

  window = NSWindow(
      contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
      styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView, .texturedBackground],
      backing: .buffered, defer: false)
  window.titlebarAppearsTransparent = true
  window.center()
  window.setFrameAutosaveName("Main Window")
  window.contentView = NSHostingView(rootView: contentView)
  // window.makeKeyAndOrderFront(self) <- don't call it here
  DispatchQueue.main.async {
    self.window.orderOut(nil)
    self.window.makeKeyAndOrderFront(nil)
  }
}

我只是在AppDelegate中使用了下面的变体,ContentView等的内容可以任意

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Create the SwiftUI view that provides the window contents.
    let contentView = ContentView()
        .edgesIgnoringSafeArea(.top) // to extend entire content under titlebar 

    // Create the window and set the content view. 
    window = NSWindow(
        contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
        styleMask: [.titled, .closable, .miniaturizable, .texturedBackground, .resizable, .fullSizeContentView],
        backing: .buffered, defer: false)
    window.center()
    window.setFrameAutosaveName("Main Window")

    window.titlebarAppearsTransparent = true // as stated
    window.titleVisibility = .hidden         // no title - all in content

    window.contentView = NSHostingView(rootView: contentView)
    window.makeKeyAndOrderFront(nil)
}

backup

只是想了解更多有关 SwiftUI 应用程序生命周期的信息。

您需要将 window 样式设置为 HiddenTitleBarWindowStyle :

WindowGroup {
    ContentView()
}.windowStyle(HiddenTitleBarWindowStyle())

纯 SwiftUI 中的最小解决方案。

@main
struct X_App: App {

var body: some Scene {
    WindowGroup {
        ContentView()
       .edgesIgnoringSafeArea(.top) 
           
    }.windowStyle(.hiddenTitleBar)
 }}