简体   繁体   中英

SwiftUI NavigationLink in the list doesn't get the right detail page with isActive

I just want to simply navigate to a detail page from a List if press any cell. I have a list like this: 在此处输入图像描述

When I click cell c it gets d or others. Rather than this page.

在此处输入图像描述

Here is my code:

struct ContentView: View {

    var items = ["a", "b", "c", "d"]
    @State var isCellSelected = false

    var body: some View {
        NavigationView {
            List {
                ForEach(items.indices, id: \.self) { index in

                    NavigationLink(
                        destination: Text("\(items[index])"),
                                        isActive: $isCellSelected,
                        label: {
                                    RowView(text: items[index])
                        })
                }
            }
        }

    }
}

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

struct RowView: View {

    var text: String
    var body: some View {
        VStack {
            Text(text)
        }
    }
}

If I remove isActive: $isCellSelected then it works as expected. I need to use isCellSelected to pop back to root view. Not sure how to fix this issue.

Any help? thanks!

EDIT

Update removed isActive and try set selection = nil

truct DetailView: View {

    var text: String
    @Binding var isCellSelected: Int?

    var body: some View {
        VStack {
            Text(text)
            Button("Back") {
                isCellSelected = nil
               }
        }
    }
}

struct ContentView: View {

    var items = ["a", "b", "c", "d"]
    @State var selectedTag: Int? = nil
    var body: some View {
        NavigationView {
            List {
                ForEach(items.indices, id: \.self) { index in

                    NavigationLink(
                        destination: DetailView(text: "\(items[index])", isCellSelected: $selectedTag),
                        tag: index,
                                                selection: $selectedTag,
                        label: {
                            RowView(text: items[index])
                        })
                }
            }
        }

    }
}

When press Back button, doesn't go back.

It is not recommended to share a single isActive state among multiple NavigationLink s.

Why don't you use selection instead of isActive ?

struct ContentView: View {
    
    var items = ["a", "b", "c", "d"]
    @State var selectedTag: Int? = nil //<-
    
    var body: some View {
        NavigationView {
            List {
                ForEach(items.indices, id: \.self) { index in
                    
                    NavigationLink(
                        destination: Text("\(items[index])"),
                        tag: index, //<-
                        selection: $selectedTag, //<-
                        label: {
                            RowView(text: items[index])
                        })
                }
            }
        }
        
    }
}

You can set nil to selectedTag to pop back. Seems NavigationLink in List does not work as I expect. Searching for workarounds and update if found.


A dirty workaround:

(Tested with Xcode 12.3/iPhone simulator 14.3. Please do not expect this to work on other versions of iOS including future versions.)

struct DetailView: View {

    var text: String
    @Binding var isCellSelected: Bool

    var body: some View {
        VStack {
            Text(text)
            Button("Back") {
                isCellSelected = false
            }
        }
    }
}
struct Item {
    var text: String
    var isActive: Bool = false
}
struct ContentView: View {

    @State var items = ["a", "b", "c", "d"].map {Item(text: $0)}
    @State var listId: Bool = false //<-

    var body: some View {
//        Text(items.description) // for debugging
        NavigationView {
            List {
                ForEach(items.indices) { index in
                    NavigationLink(
                        destination:
                            DetailView(text: "\(items[index].text)",
                                       isCellSelected: $items[index].isActive)
                            .onAppear{ listId.toggle() } //<-
                        ,
                        isActive: $items[index].isActive,
                        label: {
                            RowView(text: items[index].text)
                        })

                }
            }
            .id(listId) //<-
        }
    }
}

Another workaround:

struct DetailView: View {

    var text: String
    @Binding var isCellSelected: Int?

    var body: some View {
        VStack {
            Text(text)
            Button("Back") {
                isCellSelected = nil
            }
        }
    }
}
struct ContentView: View {

    var items = ["a", "b", "c", "d"]
    @State var selectedTag: Int? = nil

    var body: some View {
        NavigationView {
            ZStack {
                ForEach(items.indices) { index in
                    NavigationLink(
                        destination:
                            DetailView(text: "\(items[index])",
                                       isCellSelected: $selectedTag),
                        tag: index,
                        selection: $selectedTag,
                        label: {
                            EmptyView()
                        })
                }
                List {
                    ForEach(items.indices) { index in
                        Button(action: {
                            selectedTag = index
                        }) {
                            HStack {
                                RowView(text: items[index])
                                Spacer()
                                Image(systemName: "chevron.right")
                                    .foregroundColor(Color.secondary)
                            }
                        }
                    }
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM