iosswiftxcodeswiftuiswiftui-list

Push view controller from List in SwiftUI


I am in learning phase of SwiftUI.

During this I have created one tab view which has 4 tabs, out of which on last tab, there is list which has following array

struct NavItem {
    let id: String
    let text: String
}

struct ServicesView: View {

    @State private var listItems: [NavItem] = [NavItem(id: "1", text: "Profile"),
                                                      NavItem(id: "2", text: "Leave"),
                                                      NavItem(id: "3", text: "How to use"),
                                                      NavItem(id: "4", text: "About Us"),
                                                   NavItem(id: "5", text: "Logout")]

Using LIST I am able to display the same in view correctly, only problem I am facing is I am not able to push the new on selection of any item

 var body: some View {

                NavigationView {
                    List (selection: $selection) {
                                ForEach(listItems, id:\.id) { item in
                                    Button(action: {
                                        if(item.id == "1"){
                                            print("navigate to ----> " + item.text)
                                            NavigationLink(destination: ProfileView()) {
                                                Text("Show Detail View")
                                            }
                                        }
                                    }) {
                                        Text(item.text)
                                            .foregroundStyle(.black)
                                    }
                                    .padding(10)
                                    .listRowInsets(.init(top: 0,leading: -5, bottom: 0, trailing: -5))
                                    .frame(minWidth: 111, idealWidth: .infinity, maxWidth: .infinity, alignment: .leading)
                                    .tag(item.id)
                                    .background(Color.clear)
                                }
                            }
                }
}

When I add navigationLink inside LIST, it gives me warning like below,

Result of 'NavigationLink<Label, Destination>' initializer is unused

I am able to print on console, but my list is not navigating to Profileview.

What am I doing wrong?


Solution

  • NavigationLink represents a kind of a View, it's not a function to execute when you put it in Button action. You have to bring it out of closure.

    Updated: There is a condition to trigger push action to ProfileView, so this is a trick:

    @State private var isActive: Bool = false
    ...
    NavigationView {
        List {
            ForEach(listItems, id:\.id) { item in
                Button {
                    isActive = item.id == "1"
                } label: {
                    Text(item.text)
                        .foregroundStyle(.black)
                }
            }
        }
        .background {
            NavigationLink(destination: ProfileView(), isActive: isActive) {
                EmptyView()
            }
            .hidden()
        }
    }
    

    Note: NavigationView was deprecated, you may consider using NavigationStack instead.

    @State private var path: NavigationPath = .init()
    ...
    NavigationStack(path: $path) {
        List {
            ForEach(listItems, id:\.id) { item in
                Button {
                    if item.id == "1" {
                        path.append(item)
                    }
                } label: {
                    Text(item.text)
                        .foregroundStyle(.black)
                }
            }
        }
        .navigationDestination(for: NavItem.self) { item in
            ProfileView()
        }
    }