Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI macOS right sidebar inspector

I have a document-based SwiftUI app. I'd like to make a inspector sidebar like the one in Xcode.

Starting with Xcode's Document App template, I tried the following:

struct ContentView: View {
    @Binding var document: DocumentTestDocument
    @State var showInspector = true

    var body: some View {
        HSplitView {
            TextEditor(text: $document.text)
            if showInspector {
                Text("Inspector")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
        }
        .toolbar {
            Button(action: { showInspector.toggle() }) {
                Label("Toggle Inspector", systemImage: "sidebar.right")
            }
        }
    }
}

Which yielded:

Screenshot

How can I extend the right sidebar to full height like in Xcode?

NavigationView works for left-side sidebars, but I'm not sure how to do it for right-side sidebars.

like image 668
Taylor Avatar asked Jan 31 '21 00:01

Taylor


1 Answers

Here is some stripped down code that I have used in the past. It has the look and feel that you want.

It uses a NavigationView with .navigationViewStyle(.columns) with essentially three panes. Also, the HiddenTitleBarWindowStyle() is important.

The first (navigation) pane is never given any width because the second (Detail) pane is always given all of the width when there is no Inspector, or all of the width less the Inspector's width when it's present. The ToolBar needs to be broken up and have its contents placed differently depending on whether the Inspector is present or not.

@main
struct DocumentTestDocumentApp: App {
    var body: some Scene {
        DocumentGroup(newDocument: DocumentTestDocument()) { file in
            ContentView(document: file.$document)
        }
        .windowStyle(HiddenTitleBarWindowStyle())
    }
}

struct ContentView: View {
    @Binding var document: DocumentTestDocument
    @State var showInspector = true
    var body: some View {
        GeometryReader { window in
            if showInspector {
                NavigationView {
                    TextEditor(text: $document.text)
                        .frame(minWidth: showInspector ? window.size.width - 200.0 : window.size.width)
                        .toolbar {
                            LeftToolBarItems(showInspector: $showInspector)
                        }
                    Inspector()
                        .toolbar {
                            RightToolBarItems(showInspector: $showInspector)
                        }
                }
                .navigationViewStyle(.columns)
            } else {
                NavigationView {
                    TextEditor(text: $document.text)
                        .frame(width: window.size.width)
                        .toolbar {
                            LeftToolBarItems(showInspector: $showInspector)
                            RightToolBarItems(showInspector: $showInspector)
                        }
                }
                .navigationViewStyle(.columns)
            }
        }
    }
}

struct LeftToolBarItems: ToolbarContent {
    @Binding var showInspector: Bool
    var body: some ToolbarContent {
        ToolbarItem(content: { Text("test left toolbar stuff") } )
    }
}

struct RightToolBarItems: ToolbarContent {
    @Binding var showInspector: Bool
    var body: some ToolbarContent {
        ToolbarItem(content: { Spacer() } )
        ToolbarItem(placement: .primaryAction) {
            Button(action: { showInspector.toggle() }) {
                Label("Toggle Inspector", systemImage: "sidebar.right")
            }
        }
    }
}

struct Inspector: View {
    var body: some View {
        VStack {
            Text("Inspector Top")
            Spacer()
            Text("Bottom")
        }
    }
}
like image 99
Chuck H Avatar answered Oct 16 '22 08:10

Chuck H