SwiftUI macos NSWindow instance
Although I am not entirely sure this is exactly the right approach, based on the answer to this question: https://stackoverflow.com/a/63439982/792406 I have been able to access the NSWindow
instance and modify its appearance.
For quick reference, here's a working example based on the original code provided by Asperi using xcode 12.3
, swift 5.3
, and the SwiftUI App Life cycle.
@main
struct testApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class Store {
var window: NSWindow
init(window: NSWindow) {
self.window = window
self.window.isOpaque = false
self.window.backgroundColor = NSColor.clear
}
}
struct ContentView: View {
@State private var window: NSWindow?
var body: some View {
VStack {
Text("Loading...")
if nil != window {
MainView(store: Store(window: window!))
}
}.background(WindowAccessor(window: $window))
}
}
struct MainView: View {
let store: Store
var body: some View {
VStack {
Text("MainView with Window: \(store.window)")
}.frame(width: 400, height: 400)
}
}
struct WindowAccessor: NSViewRepresentable {
@Binding var window: NSWindow?
func makeNSView(context: Context) -> NSView {
let view = NSView()
DispatchQueue.main.async {
self.window = view.window
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) {}
}
How to access NSWindow from @main App using only SwiftUI?
Basically, I'm trying to do something like:
LoginView(store: AuthStore(window: window))
Here is a demo of possible approach (with some replicated entities)
class AuthStore {
var window: NSWindow
init(window: NSWindow) {
self.window = window
}
}
struct DemoWindowAccessor: View {
@State private var window: NSWindow? // << detected in run-time so optional
var body: some View {
VStack {
if nil != window {
LoginView(store: AuthStore(window: window!)) // << usage
}
}.background(WindowAccessor(window: $window))
}
}
struct WindowAccessor: NSViewRepresentable {
@Binding var window: NSWindow?
func makeNSView(context: Context) -> NSView {
let view = NSView()
DispatchQueue.main.async {
self.window = view.window // << right after inserted in window
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) {}
}
struct LoginView: View {
let store: AuthStore
var body: some View {
Text("LoginView with Window: \(store.window)")
}
}
SwiftUI on MacOS. - Opening a new Window
Make your function generic and add view constraint.
static func newWindow<Content: View>(forSpecialView view: Content, title: String = "new Window") { // <-- Here
Another good and easy solution is to use View
extension.
extension View {
private func newWindowInternal(with title: String) -> NSWindow {
let window = NSWindow(
contentRect: NSRect(x: 20, y: 20, width: 680, height: 600),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered,
defer: false)
window.center()
window.isReleasedWhenClosed = false
window.title = title
window.makeKeyAndOrderFront(nil)
return window
}
func openNewWindow(with title: String = "new Window") {
self.newWindowInternal(with: title).contentView = NSHostingView(rootView: self)
}
}
Usage:
struct ContentView: View {
var body: some View {
Button(action: {
ContentViewNewWindow().openNewWindow()
}) {
Text("Open New Window")
}
}
}
macOS SwiftUI, content does not fill NSWindow without titlebar
It looks I've reproduced what you might have
window.contentView =
NSHostingView(rootView:
Rectangle().fill(Color.red)
.ignoresSafeArea() // << works !!
.frame(width: 640, height: 480)
// .ignoresSafeArea() // << issue when here !!
)
More findings: no issue even with ignoresSafeArea
at the end when to use min W/H instead of strict frame for window, ie.
.frame(minWidth: 640, minHeight: 480)
.ignoresSafeArea()
Related Topics
Detect Ethernet/Wifi Network Change
Why Is There a Memory Leak at String Creation in Swift
Case Insensitive Dictionary in Swift
How to Pass an Error Pointer in the Swift Language
Adding Nscoding as an Extension
Using a Property as a Default Parameter Value for a Method in the Same Class
How to "Append" to an Immutable Dictionary in Swift
Check Availability in Switch Statement
Swift Only -- Reading from Nsinputstream
Swift Diffabledatasource Make Insert&Delete Instead of Reload
Get an Error When Trying to Get All the Photos from Phassetcollection.Fetchassetcollections