10

I am trying to remove the chevron that appears on the right of the screen with a navigationLink that contains a view. This is my code below:

        NavigationView {
        List {
             NavigationLink(destination: DynamicList()) {
                  ResultCard()
             }
      ...
      }

Other answers on Stack Overflow have recommended using something like the below:

NavigationLink(...)
   .opacity(0)

However, this doesn't work in my case since bringing the opacity down to 0 also removes the view that I am trying to display. This is also the case with '.hidden'. I've searched everywhere and the only somewhat working solution I could find was to alter the padding in order to 'push' the chevron off of the side, but this is a poor solution since the 'ResultCard' view will appear wonky/off-centre on different display sizes.

Perhaps it isn't possible to remove the chevron - and if this is the case, is there any other way I can allow the user to tap the 'ResultCard' view and be taken to a new page, that isn't through a navigation link?

I'm banging my head on the wall so any ideas are very much appreciated.

HarryW
  • 155
  • 2
  • 7

4 Answers4

14

You can use an .overlay on your label view with a NavigationLink with an EmptyView() set as its label:


struct ContentView : View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Link 1", destination: Text("Hi"))
                Text("Test")
                    .overlay(NavigationLink(destination: Text("Test"), label: {
                        EmptyView()
                    }))
            }
        }
    }
}

Example of overlay navigation

Update: Another solution, which seems to work with other types of Views besides Text:

struct ContentView : View {
    @State private var linkActive = false
    
    var body: some View {
        NavigationView {
            List {
                NavigationLink("Link 1", destination: Text("Hi"))
                Button(action: { linkActive = true }) {
                    Image(systemName: "pencil")
                }.overlay(VStack {
                    if linkActive {
                        NavigationLink(destination: Text("Test"), isActive: $linkActive) {
                            EmptyView()
                        }.opacity(0)
                    }
                })
            }
        }
    }
}

jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • Thanks for your answer - this does appear to work when the navigation link contains Text("test"), but there is still a chevron when using a view. Strange! – HarryW Feb 16 '21 at 20:09
  • Just updated my answer with another solution that works with another view type – jnpdx Feb 16 '21 at 20:26
  • 2
    I needed to add `.hidden()` to the `NavigationLink` (for iOS 14) otherwise the chevron still appears. My `.overlay` is being applied to an `HStack` so I can substitute my own icon on the right. It's all very hacky and I hope Apple addresses this. – Bob Peterson Mar 14 '21 at 20:55
  • The first method, applying the .overlay directly to the View, seems to work normally in Xcode 13.2.1 as of Jan 2022. Thanks. – Jaidyn Belbin Jan 13 '22 at 06:56
2

This worked for me, building on @wristbands's solution and targeting iOS 16 using Xcode 14.1:

struct ContentView : View {
    var body: some View {
        NavigationStack {
            List {
                Text("View")    // your view here
                .overlay {
                    NavigationLink(destination: { Text("Test") }, 
                                   label: { EmptyView() })
                        .opacity(0)
                }
            }
        }
    }
}
1

The Update solution from jnpdx almost worked for me, but it messed up the animation to the next view. Here's what worked for me (is actually simpler than jnpdx's answer):

struct ContentView : View {
    @State private var linkActive = false
    
    var body: some View {
        NavigationView {
            List {
                Button(action: { linkActive = true }) {
                    Image(systemName: "pencil")
                }.overlay(
                    NavigationLink(
                        isActive: $linkActive,
                        destination: { Text("Test") },
                        label: { EmptyView() }
                    ).opacity(0)
                )
            }
        }
    }
}
wristbands
  • 1,021
  • 11
  • 22
0

Here are two alternative variations using .background():

// Replicate the iPhone Favorites tab with the info button
// - Compose a button to link from a NavigationView to a next view
// - Use this when you want to hide the navigation chevron decoration
// - and/or to have a button trigger the link

struct NavigationLinkButton<Destination: View, Label: View>: View {
    @Binding var selectedID: String?
    @State var rowID: String
    @ViewBuilder var destination: () -> Destination
    @ViewBuilder var label: () -> Label

    var body: some View {
        HStack {
            Spacer()
            Button {
                selectedID = rowID
            } label: {
                label()
            }
            .buttonStyle(.plain) // prevent List from processing *all* buttons in the row
            .background {
                NavigationLink("", tag: rowID, selection: $selectedID) {
                    destination()
                }
                .hidden()
            }
        }
    }
}
// Replicate the iOS Spotlight search for contacts with action buttons
// - Compose a list row to link from a NavigationView to a next view
// - Use this when you want to hide the navigation chevron decoration
// - and add action buttons

struct NavigationLinkRowHidingChevron<Destination: View, Label: View>: View {
    @Binding var selectedID: String?
    @State var rowID: String
    @ViewBuilder var destination: () -> Destination
    @ViewBuilder var label: () -> Label

    var body: some View {
        ZStack {
            // Transparent button to capture taps across the entire row
            Button("") {
                selectedID = rowID
            }
            label()
        }
        .background {
            NavigationLink("", tag: rowID, selection: $selectedID) {
                destination()
            }
            .hidden()
        }
    }
}
// Example Usages
//
// @State private var selectedID: String?
// @State private var editMode: EditMode = .inactive
//
// ... and then in the body:
// List {
//    ForEach(items) { item in
//        row(for: item)
//            .swipeActions(edge: .leading, allowsFullSwipe: true) {
//                ...
//            }
//            .contextMenu {
//                ...
//            }
//            .onDrag({
//                ...
//            })
//            // Overlay so that a tap on the entire row will work except for these buttons
//            .overlay {
//                // Hide info button just as with Phone Favorites edit button
//                if editMode == .inactive {
//                    NavigationLinkHidingChevron(selectedID: $selectedID, rowID: item.id) {
//                        // Destination view such as Detail(for: item)
//                    } label: {
//                        // Button to activate nav link such as an  button
//                    }
//                }
//            }
//    }
//    .onDelete(perform: deleteItems)
//    .onMove(perform: moveItems)
// }
//
// ... or this in the body:
// NavigationLinkHidingChevron(selectedID: $selectedID, rowID: contact.id) {
//    // Destination view such as Detail(for: item)
// } label: {
//    // Content for the list row
// }
// .contextMenu {
//    ...
// }
// .overlay {
//    HStack(spacing: 15) {
//        // Right-justify the buttons
//        Spacer()
//        // Buttons that replace the chevron and take precedence over the row link
//    }
// }

Collierton
  • 539
  • 5
  • 10
  • From Apple documentation: "Note If you want to remove the platform-appropriate styling — such as row separators or automatic disclosure indicators — from your list, consider using LazyVStack instead. For more information on working with lazy stacks, see Creating performant scrollable stacks." – user1204493 May 13 '23 at 21:58