How can I pass subviews SwiftUI views in my model?

New to SwiftUI and I cannot find a way to pass multiple views in my model which populates the List in the NavigationStack .

(Below I have placed all my code into one file to make it easier to examine)

I populate List from MainMenuFramework , which would hold the title, graphic, and eventually a subMenu to go to for each List element. i.e. SubView1, SubView2, and so on.

When within the MainMenuFramework I try to add let subMenu : View I first am told to add it as any View . But then I have to make MainMenuFramework conform to the Equatable protocol. And from there I am told that MainMenuFramework has to conform to Hashable, even though it is.

The real problem is that I am falling deeper into the well and am too new to understand what is happening. Is there perhaps a way to pass a pointer to the subviews?

I don’t just want the answer, I’d like to understand the process as well.

Thank you.

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        NavigationStack {
            ZStack {
                List(MainMenuData.mainMenuFramework) { menuItem in
                    NavigationLink {
//                      menuItem.subMenu
                    } label: {
                        ListCell(framework: menuItem)
                    }


                }
                .navigationTitle("Main Menu")
            }
        }
    }
}

struct ListCell: View {
    
    let framework : MainMenuFramework
    
    var body: some View {
        HStack {
            VStack(alignment: .center){
                Image(systemName: framework.imageName)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 50, height: 50, alignment: .center)
            }
            Text(framework.description)
                .font(.title)
                .padding(.leading, 30)
        }
        .listRowInsets(.init(top: 10,
                     leading: 10,
                     bottom: 10,
                     trailing: 10))

    }
}

struct FrameworkTitleView: View{

    let framework : MainMenuFramework
    
    var body: some View {
    
        VStack {
            Image(systemName: framework.imageName)
                .resizable()
                .frame(width: 75, height: 75)
                .padding(.top, 20)
                .padding(.bottom, 5)
            Text(framework.name)
                .font(.title2)
                .fontWeight(.semibold)
                .foregroundColor(Color(.label))
                .scaledToFit()
                .minimumScaleFactor(0.6)
        }
        .padding()
    
    }
}

struct MainMenuFramework: Hashable, Identifiable {
        

    let id              :   Int
    let name            :   String
    let imageName       :   String
    let urlString       :   String
    let description :   String
}


struct MainMenuData {

    static let mainMenuFramework = [
        
        MainMenuFramework(
            id: 001,
            name: "Setup",
            imageName: "list.clipboard",
            urlString: "",
            description: "Setup"),
        
        MainMenuFramework(
            id: 002,
            name: "Account",
            imageName: "person.circle",
            urlString: "",
            description: "Account Settings"),
        
        MainMenuFramework(
            id: 003,
            name: "Help",
            imageName: "questionmark.circle",
            urlString: "",
            description: "Support")

    ]

}
struct DetailView: View {
    var body: some View {
        Text("This is the detail view 1")
    }
}

struct DetailView2: View {
    var body: some View {
        Text("This is the detail view 2")
    }
}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

@SergioQ

I’m not sure if I understand your problem correctly.

I’m getting that you want to have different subviews associated with each element in the List and navigate to them when tapping on the corresponding item. Is this correct?

Correct. The model MainMenuData populates the List in my ContentView, with the icons, and text for each item. Ideally I would like to place the subview for each item in MainMenuData as well, to be placed in NavigationLink.

However, I cannot add a subView property in the MainMenuData without going down a rabbit hold that I never come out of.

One approach would be to store an identifier in the model that represents the subview, and then use that identifier to choose which subview to display.

Here’s how you can modify your code to achieve this:

  1. Add an enum SubMenuType to represent the different submenus.
  2. Add a subMenuType: SubMenuType property to the MainMenuFramework .
  3. Use a switch statement inside the NavigationLink to decide which view to navigate to.

For example here’s a modified code:

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        NavigationView {
            List(MainMenuData.mainMenuFramework) { menuItem in
                NavigationLink {
                    switch menuItem.subMenuType {
                    case .detailView1:
                        DetailView()
                    case .detailView2:
                        DetailView2()
                    }
                } label: {
                    ListCell(framework: menuItem)
                }
            }
            .navigationTitle("Main Menu")
        }
    }
}

// ... (keep the rest of your code as-is)

enum SubMenuType {
    case detailView1
    case detailView2
}

struct MainMenuFramework: Hashable, Identifiable {
    let id              :   Int
    let name            :   String
    let imageName       :   String
    let urlString       :   String
    let description :   String
    let subMenuType     :   SubMenuType
}

struct MainMenuData {
    static let mainMenuFramework = [
        MainMenuFramework(
            id: 001,
            name: "Setup",
            imageName: "list.clipboard",
            urlString: "",
            description: "Setup",
            subMenuType: .detailView1
        ),
        MainMenuFramework(
            id: 002,
            name: "Account",
            imageName: "person.circle",
            urlString: "",
            description: "Account Settings",
            subMenuType: .detailView2
        ),
        MainMenuFramework(
            id: 003,
            name: "Help",
            imageName: "questionmark.circle",
            urlString: "",
            description: "Support",
            subMenuType: .detailView1
        )
    ]
}

// ... (keep the rest of your code as-is)

With these changes, you avoid storing views directly in your model and instead store an identifier that represents the subview. This makes the model simpler and more reusable. When you want to add new subviews, you can just add new cases to the SubMenuType enum and handle them in the switch statement inside the NavigationLink .

1 Like

I did something similar to that. Posted what I did here: How can I pass different SwiftUI views in my model? - Stack Overflow