Create a NavigationSplitView on macOS with transparent background?

299 views Asked by At

Working on macOs 14 with SwiftIU, and have a NavigationSplitView. I want to set its background to be transparent. I am basically trying to recreate the look of the Apple Home app:

enter image description here

Using the Swift Introspection library, I am able to set the detail and content view backgrounds to be clear, but I cannot get the sidebar or toolbar to be transparent.

First, here is my current code:

import SwiftUI
import SwiftUIIntrospect

struct ContentView: View {
    var body: some View {
        ZStack {
            Color.green
        
        
        NavigationSplitView {
            Text("Sidebar")
        } content: {
            Text("Content")
        } detail : {
            Text("detail")
        }.introspect(.navigationSplitView, on: .macOS(.v14)) { split in
            
            let c = split.delegate as! NSViewController
            
               let removeBackgrounds = {
            
                   c.children.forEach { controller in
                       controller.parent?.view.wantsLayer = true
                       controller.parent?.view.layer?.backgroundColor = bgColor
                       controller.view.clearBackgrounds()
                   }
                    
               }
               
               removeBackgrounds() // run now...
               DispatchQueue.main.async(execute: removeBackgrounds)
           }
        }
    }
}

#Preview {
    ContentView()
}


let bgColor = NSColor.clear.cgColor
private extension NSView {
    func clearBackgrounds() {
        wantsLayer = true
        layer?.backgroundColor = bgColor
        for subview in subviews {
            subview.clearBackgrounds()
        }
    }
}

This is modeled on this post, which does the same for NavigationSplitView but for iOS.

This gives me:

enter image description here

If I set the color to blue, it seems to work (except for the tool bar), but does not work for clear.

enter image description here

I have published a project with the code above: https://github.com/mikechambers/TransparentNavigationSplitViewExample

(Need to run Pod install and then launch from the workspace)

I've been banging my head against this for a couple of days now (trying to get up to speed on the underlying architecture).

Any suggestions or pointers would be appreciated.

1

There are 1 answers

1
ChrisR On

I got roughly as far as you, but without introspect, thanks to this post.
Did not yet find a way to make the toolbar transparent ...

Actually .windowStyle(.hiddenTitleBar) does hide the toolbar and everything gets transparent, but then you can't have a toolbar anymore ... (or only a custom one).

enter image description here

struct VisualEffect: NSViewRepresentable {
    func makeNSView(context: Self.Context) -> NSView {
        let view = NSVisualEffectView()
        view.material = .sidebar
        return view
    }
    func updateNSView(_ nsView: NSView, context: Context) { }
}


@main
struct TransparentApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .background(VisualEffect())
        }
//        .windowStyle(.hiddenTitleBar) // this hides the toolbar
    }
}

struct ContentView: View {
    var body: some View {
        
        NavigationSplitView {
            List {
                Label("Home", systemImage: "house")
                Label("Discover", systemImage: "star")
            }
//            .toolbarBackground(.hidden)
//            .toolbarBackground(.ultraThinMaterial)
        } detail: {
            Text("some content")
        }
        .navigationTitle("Transparent")
//        .presentedWindowToolbarStyle(.unifiedCompact)
//        .toolbarTitleDisplayMode(.inline)
    }
}