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)
}
只是想了解更多有关 SwiftUI 应用程序生命周期的信息。
您需要将 window 样式设置为 HiddenTitleBarWindowStyle :
WindowGroup {
ContentView()
}.windowStyle(HiddenTitleBarWindowStyle())
纯 SwiftUI 中的最小解决方案。
@main
struct X_App: App {
var body: some Scene {
WindowGroup {
ContentView()
.edgesIgnoringSafeArea(.top)
}.windowStyle(.hiddenTitleBar)
}}
我正在使用 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)
}
只是想了解更多有关 SwiftUI 应用程序生命周期的信息。
您需要将 window 样式设置为 HiddenTitleBarWindowStyle :
WindowGroup {
ContentView()
}.windowStyle(HiddenTitleBarWindowStyle())
纯 SwiftUI 中的最小解决方案。
@main
struct X_App: App {
var body: some Scene {
WindowGroup {
ContentView()
.edgesIgnoringSafeArea(.top)
}.windowStyle(.hiddenTitleBar)
}}