Search code examples
iosipadswiftui

Weird behavior of NavigationLink on iPad


In my app, I have a Scrollview containing NavigationLinks embedded in a NavigationView. On the iPad, pressing the NavigationLinks causes something weird to happen. The first time one of the items is pressed, it works perfectly fine, and shows the detail view. Any subsequent presses on other items either do nothing or shows the detail view of a previously pressed item. Sometimes it will work for a few items in a row, but then freezes again.

It seems like a problem with the navigation stack?

This simplified example shows the error on an 11" iPad pro running iOS 13.7

struct ContentView: View {
    var body: some View {
        NavigationView {
            ScrollView {
                ForEach(0..<20) { index in
                    NavigationLink(destination: Text("\(index)")) {
                        Text("\(index)")
                            .padding()
                            .frame(width: 100, height: 100)
                            .background(Color.green)
                    }
                }
            }
        }
    }
}

Solution

  • Yes, it looks like a bug. You can file feedback to Apple.

    Meanwhile, here is possible workaround. Tested with Xcode 11.7 / iOS 13.7

    struct ContentView: View {
        @State private var selection = -1
        @State private var isActive = false
    
        var body: some View {
            NavigationView {
                ScrollView {
                    ForEach(0..<20) { index in
                        Button(action: {
                            self.selection = index
                            self.isActive = true
                        } ) {
                            Text("\(index)")
                                .padding()
                                .frame(width: 100, height: 100)
                                .background(Color.green)
                        }
                    }
                }
                .background(NavigationLink(destination: Text("\(selection)"),
                    isActive: $isActive) { EmptyView() })
            }
        }
    }