iOS 16 NavigationLinks in nested Lists unclickable

467 Views Asked by At

I am running xCode 14.2 on iOS 16.2 simulator and iOS 16.1.2 device.

I have, in my app, NavigationLinks in sublists that are implemented as nested Lists. After updating my xCode, suddenly the NavigationLinks have become unclickable. It looks like something happened to the touch target where the NavigationLink itself cannot be clicked, and only some tiny background sliver is clickable.

Here is sample code reproducing the issue:

import SwiftUI

@available(iOS 16.0, *)
struct ContentView: View {

    var body: some View {
        NavigationStack {
            List {
                List {
                    NavigationLink("Mint") { ColorDetail(color: .mint) }
                    NavigationLink("Pink") { ColorDetail(color: .pink) }
                    NavigationLink("Teal") { ColorDetail(color: .teal) }
                }.listStyle(.plain)
                List {
                    NavigationLink("Red") { ColorDetail(color: .red) }
                    NavigationLink("Blue") { ColorDetail(color: .blue) }
                    NavigationLink("Black") { ColorDetail(color: .black) }
                }.listStyle(.plain)
            }.listStyle(.plain)
            .navigationTitle("Colors")
        }
    }
}

struct ColorDetail: View {
    var color: Color

    var body: some View {
        color.navigationTitle(color.description)
    }
}

Here is a screencast of what it looks like: https://i.stack.imgur.com/Ugaky.jpg. Basically, the bulk of the color label is unclickable, but the edges are clickable. But even when they are clicked, they behave funkily, with multiple links being triggered. This happens with both NavigationStack and NavigationView.

Could someone shed some insight into why this is happening and how to fix it? It works great on < iOS 15

EDIT: I tried going away from nested lists to use sections instead. But it looks to me like as soon as a list item gets a little complicated, the navigation completely breaks. Here is an example where I add a title to each list item, but each navigation link should still go to its own ColorDetail view. However, the navigation doesn't work as you'd expect:

struct ContentView: View {

    var body: some View {
        NavigationStack {
            List {
                ForEach(Range(1...3), id: \.self) { num in
                    Section {
                        VStack {
                            Text("Title: \(num)")
                            NavigationLink("Mint") { ColorDetail(color: .mint) }
                            NavigationLink("Pink") { ColorDetail(color: .pink) }
                            NavigationLink("Teal") { ColorDetail(color: .teal) }
                        }
                    }
                }
            }.listStyle(.plain).navigationTitle("Colors")
        }
    }
}
3

There are 3 best solutions below

1
On

You can't nest lists. You got lucky in iOS 15 where you got the desired outcome, but that was a side effect. That doesn't work, as you see. Your better option is to have one List, and then use Section in place of your other Lists. Since you use the .plain listStyle, it will all render as one list.

struct ContentView: View {
    var body: some View {
        NavigationStack {
            List {
                Section {
                    NavigationLink("Mint") { ColorDetail(color: .mint) }
                    NavigationLink("Pink") { ColorDetail(color: .pink) }
                    NavigationLink("Teal") { ColorDetail(color: .teal) }
                }
                Section {
                    NavigationLink("Red") { ColorDetail(color: .red) }
                    NavigationLink("Blue") { ColorDetail(color: .blue) }
                    NavigationLink("Black") { ColorDetail(color: .black) }
                }
            }.listStyle(.plain)
            .navigationTitle("Colors")
        }
    }
}
0
On

List is suitable for re-usable row. One of your NavigationLink is unique. So please switch to use ScrollView.

Apple is still develop SwiftUI and change it frequently, still not stable as my experience.

0
On

You are overlapping the lists on the view, the UI is drawing them on top of each other. In you would like to create sections for your colors with in the NavigationStack, I have created this sample for to provide an idea how you can use NavigationStack with list of items.


import SwiftUI

struct MyColor: Hashable, Identifiable {
    var id: UUID
    var color: Color
}

struct MySection: Hashable, Identifiable {
    var id: UUID
    var name: String
    var myColors: [MyColor]
    
    static let sections = [
        MySection(id: UUID(), name: "First Section", myColors: [MyColor(id: UUID(), color: .mint),
                                                                MyColor(id: UUID(), color: .pink),
                                                                MyColor(id: UUID(), color: .teal)]),
        
        MySection(id: UUID(),  name: "Second Section", myColors: [MyColor(id: UUID(), color: .red),
                                                                  MyColor(id: UUID(), color: .blue),
                                                                  MyColor(id: UUID(), color: .black)])
    ]
}

struct ContentView: View {
    let sections: [MySection] = MySection.sections
    var body: some View {
        NavigationStack {
            List {
                // For each section
                ForEach(sections) { section in
                    // Create a section
                    Section(section.name) {
                        // create navigation link for each color in section
                        ForEach(section.myColors) { item in
                            
                            // Navigation link, provide a hashable value
                            NavigationLink(value: item) {
                                Text(item.color.description)
                            }
                        }
                    }
                }
            }
            // when you see menu item coming in you go to item detail
            .navigationDestination(for: MyColor.self) { item in
                ColorDetail(color: item.color)
            }
            .navigationTitle("Colors")
        }
    }
}

struct ColorDetail: View {
    var color: Color
    var body: some View {
        color.navigationTitle(color.description)
    }
}

Preview For Content View