swiftmacosswiftuitoolbar

How do I hide my toolbar in SwiftUI when full screened?


I have a SwiftUI app with a toolbar with multiple WindowGroups. I want all of my windows except the main one to have a toolbar with behaviour similar to the Preview app, hiding/collapsing the toolbar when it is fullscreen.

I have .presentedWindowToolbarStyle(.unified) attached to my views and .windowStyle(.titleBar) attached to my WindowGroups.

I have tried searching for methods, asked ChatGPT multiple times and I have tried to find open-source SwiftUI apps with a collapsing toolbar but they all did not work because they were either about iOS or about an AppKit app. In code, I have tried different settings of .windowStyle and .presentedWindowToolbarStyle as well as setting .windowToolbarStyle.


Solution

  • I managed to achieve this by doing the following:

    For the first step, you can create a NSViewRepresentable like so:

    struct HostingWindowFinder: NSViewRepresentable {
        var callback: (NSWindow?) -> ()
        
        func makeNSView(context: Self.Context) -> NSView {
            let view = NSView()
            DispatchQueue.main.async { self.callback(view.window) }
            return view
        }
        
        func updateNSView(_ nsView: NSView, context: Context) {
            DispatchQueue.main.async { self.callback(nsView.window) }
        }
    }
    

    Now create the custom delegate like this:

    class CustomWindowDelegate: NSObject, NSWindowDelegate {
        override init() {
            super.init()
        }
        
        func window(_ window: NSWindow, willUseFullScreenPresentationOptions proposedOptions: NSApplication.PresentationOptions = []) -> NSApplication.PresentationOptions {
            return [.autoHideToolbar, .autoHideMenuBar, .fullScreen]
        }
    }
    

    Finally, in your view, do this to set the window delegate:

    struct ContentView: View {
        private var customWindowDelegate = CustomWindowDelegate()
        
        var body: some View {
            Text("Hello World")
                .background {
                    HostingWindowFinder { window in
                        guard let window else { return }
                        window.delegate = self.customWindowDelegate
                    }
                }
        }
    }
    

    And now whenever your ContentView goes fullscreen, it will auto hide the toolbar which can be revealed by moving your cursor to the top.