swiftPunk
swiftPunk

Reputation: 1

How can I remove maximize, minimize and close button in macOS in SwiftUI-life cycle?

I am working on a project for removing maximize, minimize and close buttons which we can see in every window in every App/projects build with Xcode for macOS in SwiftUI-life cycle. How could I do this?


enter image description here


PS: Please consider I am coding on SwiftUI-life cycle/macOS and if your code or way is not compatible with that then I could not make use of it. thanks for help and your time.

Update, date 05-March-2022: The question is still open and looks for a SwiftUI approach. You can answer this question with SwiftUI api.

Upvotes: 14

Views: 6397

Answers (2)

ingconti
ingconti

Reputation: 11666

my two cents about using different approaches, integrating the previous nice solution from "shufflingb". Googling around and making some tests, I assemble another solution based on AppDelegate method. Hoping can help, I did prepare a project in gitHub with both approaches using a "const" (see below "let") to switch between approaches,

(https://github.com/ingconti/HideMacOsWindowButtons)

Here just some code for AppDelegate approach:

As a last side note, you cannot in any way to use it under Catalyst.

class MyAppDelegate: NSObject, NSApplicationDelegate {
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // 1st method:
        if USE_APP_DELEGATE{
            customize(window: NSApplication.shared.windows.first)
        }
    }
}

@main
struct HideMacOsWindowButtonsApp: App {
    
    @NSApplicationDelegateAdaptor private var appDelegate: MyAppDelegate

    var body: some Scene {
        WindowGroup {
           ContentView()
        }
    }
}

customise will do as per previous code:

//let USE_APP_DELEGATE = true
let USE_APP_DELEGATE = false

import AppKit


let ActiveNotif = NSApplication.didBecomeActiveNotification
typealias Window = NSWindow



fileprivate var count = 0

func customize(window: Window?) {

    count+=1
    
    print(USE_APP_DELEGATE ? "using App delegate" : "using notification", count)
    guard let window = window else{
        return
    }
    //window.titleVisibility = .hidden
    //window.titlebarAppearsTransparent = true
    window.isOpaque = false
    window.backgroundColor = NSColor.green

    window.standardWindowButton(.zoomButton)?.isHidden = true
    window.standardWindowButton(.closeButton)?.isHidden = true
    window.standardWindowButton(.miniaturizeButton)?.isHidden = true

}

I did add:

fileprivate var count = 0

just to verify no multiple calls (onlyy for debug).

Upvotes: 0

shufflingb
shufflingb

Reputation: 1947

Came across this question when looking to do similar myself so thought I'd add answer for posterity - or at least until Apple decides to make SwiftUI work nicely on macOS.

Anyway, the trick is to get hold of the window that holds the SwiftUI View and then tweak that. Easiest approach seems to be to listen for NSApplication's didBecomeActiveNotification and then grab a reference from NSApplication.shared mainWindow, keyWindow (or possibly filter it out by title from windows) as works best for the app in question.

Example of this using mainWindow for a helloWorld program...

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
            .frame(minWidth: 200, minHeight: 200)
            .navigationTitle("Undecorated")
            .onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification), perform: { _ in
                NSApp.mainWindow?.standardWindowButton(.zoomButton)?.isHidden = true
                NSApp.mainWindow?.standardWindowButton(.closeButton)?.isHidden = true
                NSApp.mainWindow?.standardWindowButton(.miniaturizeButton)?.isHidden = true
            })
    }
}

Notes

  1. Although the buttons are gone from the window it is important to note that the menu entries and hotkeys for maximising, hiding and killing the window are still fully operational. That functionallity has to be removed separately from customising the window appearance.

  2. The alternative method I've seen to get hold of the window is to add an dummy "Find My Window" type View to the UI that uses AppKit to create it, and grabs a reference to the window when it does so. There is a nice exposition of this approach over on LostMoa's blog here.

  3. Would be very interested if anyone has found anything better.

Upvotes: 11

Related Questions