Reputation: 341
Hi is there a way to change the window level with SwiftUI so I can make a floating window for my mac app? I am using the SwiftUI life cycle
Upvotes: 12
Views: 3575
Reputation: 1023
Slight update to @mattroberts code for macOS 14:
ContentView()
.background(WindowAccessor(window: $window))
.onChange(of: window) { _, newWindow in
if windowFloats {
newWindow?.level = .floating
} else {
newWindow?.level = .normal
}
}
.onChange(of: windowFloats) {
if windowFloats {
window?.level = .floating
} else {
window?.level = .normal
}
}
If you just want it to always float you dont need the second onChange(of:)
Upvotes: 0
Reputation: 630
You can use window.level = .floating as Alexander Sandberg put, but you likely will only want to specify this for one window not every one in your app.
That said, take a look at Asperi's post that shows you how to access a window in macOS in SwiftUI: https://stackoverflow.com/a/63439982/10844710
I will summarize the pertinent code here:
#if os(macOS)
import SwiftUI
import AppKit
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) {}
}
#endif
You then can use it in a window group at the top level of your app like so:
ContentView().background(WindowAccessor(window: $window)).onChange(of: window) { newWindow in
if windowFloats {
newWindow?.level = .floating
} else {
newWindow?.level = .normal
}
}.onChange(of: windowFloats) { floats in
if windowFloats {
window?.level = .floating
} else {
window?.level = .normal
}
}
You can include your variables as needed:
#if os(macOS)
@State var window: NSWindow?
@AppStorage("windowFloats") private var windowFloats: Bool = false
#endif
Upvotes: 6
Reputation: 1883
You can access your windows with NSApplication.shared.windows
and set the level
for each one.
For instance:
Button("Float windows") {
for window in NSApplication.shared.windows {
window.level = .floating
}
}
Upvotes: 10