NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

working with 3-column layouts

Forums > SwiftUI

I'm struggling with the sidebar of a 3-column layout for iPad.

The columns themselves are presenting properly:

1 | 2 | 3 = (Optional)Sidebar | List | Detail

However, the navigation links in column 1 are showing up in column 2, rather than column 3. And in the process, they're making it impossible to get the list view that SHOULD be shown in column 2 back.

I've also tried making the links in column 1 into modal views, but that has presented three problems:

1) some of the views are just too small to look good in the large sheets in for iPad 2) trying to implement some of the half/partial sheet options I've seen in various places (as a solution for problem 1) results in the sheets only appearing over column 1 and being cut off on the sides 3) sometimes there are navigation links in the views that should take me back to my main 3-column view and I can't figure out how to implement that properly.

For example (Keep in mind I'm working on an app to curate Audiobook libraries):

Let's say what's showing in column 2 is a list of book series. I tap one of those columns, and what shows up in column 3 is the detail view for that series. The detail view has a list of books in that series. I tap one of those, and the item shown in the detail view changes to that book.

But if I want to create a new series, I have a link to do that in column 1, and a view for creating a new series. At the end of creating the series, I want to navigate to the series detail view. But if the series creator view is presented as a sheet, the series detail view appears in the sheet, not in the main navigation view, and the navigation links for the books in the series don't go anywhere (maybe because what is being shown in the series creation sheet view isn't a Navigation View?)

I'm sorry I don't have any code to show for this. It's not really an issue I can demonstrate just by showing the code.

So, yeah. I need a way to either present sheets from the links in Column 1 that will, once I'm finished with them, allow me to navigate back to my main, 3-column layout, or I need the navigation links from Column 1 to present their views in Column 3, rather than Column 2.

   

Adding some code.

This is about as simplified as I can make the code I'm working with.

enum MySidebarOption: String, Identifiable, CaseIterable {
    var id: Int { self.hashValue }

    case anOption = "An Option"
    case anotherOption = "Another Option"

    var icon: String {
        switch self {
            case .anOption: return "photo"
            case .anotherOption: return "questionmark"
        }
    }

    @ViewBuilder
    var label: some View {
        HStack {
            Image(systemName: self.icon)
            Text(self.rawValue)
        }
    }

    @ViewBuilder
    var destination: some View {
        switch self {
            case .anOption: AView(selection: .constant(self))
            case .anotherOption: AnotherView(selection: .constant(self))
        }
    }
}

struct AView: View {
    @Binding var selection : MySidebarOption?
    @Environment(\.presentationMode) var presentationMode

    var body : some View {
        VStack(spacing: 15) {
            aButton

            anotherButton
                .font(.title2)

            cancelButton.font(.title2)
        }
    }

    private var aButton: Button<Label<Text, Image>> {
        Button(action: { doAThing() }, label: {
            Label("Do A Thing", systemImage: "gearshape")
        })
    }

    func doAThing() { print("Did the Thing") }

    private var anotherButton: Button<Label<Text, Image>> {
        Button(action: {
            doAnotherThing()
            // dismiss this view when done
            selection = nil
            presentationMode.wrappedValue.dismiss()
        }, label: {
            Label("Do Another Thing", systemImage: "photo")
        })
    }

    func doAnotherThing() { print("Did that other thing") }

    private var cancelButton: Button<Text> {
        Button(action: {
            selection = nil
            presentationMode.wrappedValue.dismiss()
        }, label: {
            Text("Fuggetabouddit")
        })
    }
}

struct Sidebar: View {
    @State private var selection :  MySidebarOption?

    var body: some View {
        List(MySidebarOption.allCases,
             selection: $selection) { item in
               ZStack { // to get rid of the chevrons
                 NavigationLink(
                    destination: item.destination,
                       label: {
                         EmptyView()
                     })
                     .opacity(0)
                item.label
             }
         }
        .listStyle(SidebarListStyle())
    }
}

struct ContentView: View {
    var body: some View {
        Sidebar()
        List()
        Detail()
    }
}

I've tried absolutely everything I can think of, but no matter what I do with regards to the action of the cancel and anotherButton buttons, the view doesn't dismiss, and as a result, after it has been presented, the second column (List) is impossible to get back to because AView is there instead.

The sidebar still works, so if I select AnotherView from the sidebar menu, the view that is being presented in the second column will change. But with those other views, same thing. Attempting to dismiss them and get List back in the middle column just doesn't work.

   

Hacking with Swift is sponsored by Instabug

SPONSORED Catch bugs as soon as they happen and know exactly why a crash occurred. Instabug's SDK grabs all the logs they need to fix bugs, crashes and performance issues in minutes instead of days. Get screenshots, device details, network logs, repro steps, and tons of other critical insights needed to resolve issues and prioritize product backlogs straight from your dashboard. It only takes a minute to integrate!

Get started now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.