ios – How to recreate Feedback.app toolbar UI on macos with SwiftUI?


I would like to recreate the toolbar area from the macOS Feedback or Mail app in SwiftUI:

  1. Content and Detail should have their own toolbars
  2. Each pane’s content should be blurred when behind the toolbar
  3. The toolbar should blur and the bottom separator should appear only when the content is scrolled behind it.
  4. The content and detail toolbars’ styles should not extend into the sidebar area.

I can accomplish #1 with both NavigationSplitView and HSplitView. But 2-3 remain elusive. I can accomplish #2 by using .toolbarBackground(...) but that breaks #4 and makes the toolbar background permanent.

Is this possible using native controls? (I know I could rebuild it using .safeAreaInset(...) and some custom scroll view position tracking.) It seems like a common pattern on macOS and is the way iOS works by default (though it does breaks there at times…).

Content:

struct ContentView: View {
    var body: some View {
        NavigationSplitView(
            sidebar: { self.toolbarView(name: "Sidebar", showDivider: false) },
            content: { self.toolbarView(name: "Content") },
            detail: { self.toolbarView(name: "Detail", showDivider: false) }
        )
    }
    
    // if `showDivider == true` the toolbar is always solid
    // if `false` then the content always shows unblurred behind the toolbar
    func toolbarView(name: String, showDivider: Bool = true) -> some View {
        VStack(spacing: 0.0) {
            if showDivider {
                Divider()
            }
            List { Text(name) }
                .toolbar {
                    ToolbarItemGroup {
                        VStack(alignment: .leading) {
                            Text(name).font(.headline)
                            Text("Subtitle").font(.subheadline).foregroundStyle(.secondary)
                        }
                        Spacer()
                        Text(name)
                    }
                }
        }
    }
    
}

App:

@main
struct NavigationSplitViewTestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .windowToolbarStyle(.unified)
        .windowStyle(.hiddenTitleBar)
        .windowResizability(.contentMinSize)
    }
}

Feedback.app
Feedback.app
Mail.app
Mail.app
Not_Working.app
Not_Working.app

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img