macosswiftuiuitoolbar

Toolbar background color


I have a project form MacOS with SwiftUI. There is a window with settings-like splitview and a toolbar, created with following code:

        Window("Settings", id: "settings") {
            NavigationSplitView {
                List {
                    NavigationLink("One", value: "one")
                    NavigationLink("Two", value: "two")
               }
            } detail: {
                ScrollView {
                    Form {
                        Section(header: Text("General")) {
                            Toggle("An option", isOn: .constant(true))
                        }
                        
                    }
                    .formStyle(.grouped)
                    .scrollContentBackground(.hidden)
                    .background(Color(NSColor.controlBackgroundColor))
                }
                .toolbar {
                    ToolbarItem(placement: .navigation) {
                        Text("Title in toolbar")
                    }
                    
                }
                //.toolba

            }
        }
        .windowToolbarStyle(.unified(showsTitle: false))
        //.windowStyle(HiddenTitleBarWindowStyle())
        .defaultSize(width: 600, height: 500)
        .windowResizability(.contentSize)

Result looks like this: enter image description here

I want the toolbar to have white background, but only above the detail part of splitview. The left sidebar part should remain as it is. How to do that?

I know about .toolbarBackground() modifier, but it changes the background over whole width of the toolbar, even on the left side of sidebar. I also know about .windowStyle(HiddenTitleBarWindowStyle()) , but that makes background transparent, so if I scroll with the detail content, it is visible under the toolbar.

It would be also nice to remove the separator horizontal line at the bottom of the toolbar.


Solution

  • When the ScrollView "touches" an unsafe area (e.g. the toolbar), it expands beyond the safe area, allowing content to flow into the unsafe area during scrolling. This is why you end up getting things like this when you use .windowStyle(.hiddenTitleBar):

    enter image description here

    If we just prevent the scroll view from touching the toolbar, the scroll view will not allow its contents to overflow the safe area. This can be done simply by adding a tiny bit (one pixel) of padding at the top.

    Then, to change the color of only the right side of the split view, add a .background(_:ignoreSafeAreaEdges:) modifier to the ScrollView, after the padding. This ignores all safe areas by default, and therefore will also fill the toolbar with the desired background. Since the ScrollView does not extend to the sidebar column, the toolbar on the sidebar column will not be affected.

    // assuming you have .windowStyle(.hiddenTitleBar) on the Window...
    
    @Environment(\.pixelLength) var pixelLength
    
    // ...
    
    ScrollView {
        // ...
    }
    .padding(.top, pixelLength)
    .background(Color(NSColor.controlBackgroundColor))
    

    Now the scroll view content is properly clipped:

    enter image description here

    Finally, as an alternative to .windowStyle(.hiddenTitleBar), you can also put .toolbarBackgroundVisibility(.hidden, for: .windowToolbar) on the ScrollView.