SwiftUI NavigationLink Hide Arrow

Viewed 24024

Is there a way to hide the arrow to the right of the navigation link view that is automatically added?

I want to show an image grid using NavigationView -> List -> HStack -> NavigationLink_1 - NavigationLink_2

The NavigationLinks have arrows and it looks weird enter image description here

17 Answers

The way it worked for me:

List { 
    ForEach(elements) { element in
        ZStack {
            CustomView(element: element)
            NavigationLink(destination: DestinationView()) {
                EmptyView()
            }.buttonStyle(PlainButtonStyle())
        }
    }
}

I got it done with this

NavigationLink(destination: DestinationView()) {
      EmptyView()
}
.frame(width: 0, height: 0)
.hidden()

The easiest way I've found is to place the navigation in the .background modifier with the opacity of zero:

List {
    Text("The cell")
        .background( NavigationLink("", destination: Text("The detail view")).opacity(0) )
}

And with this solution you don't loose the dynamic height functionality of the cells.

@State var selection: Int? = nil

var body: some View {
    let navigation = NavigationLink(destination: Text("View"), tag: 1, selection: $selection) { EmptyView() }
    return 
        VStack { 
            navigation
            Text("Tap").onTapGesture { self.selection = 1 }
        }
}

The only thing that helped me is to add .opacity(0) to NavigationLink like so:

List { 
    ForEach(elements) { element in
        ZStack {
            CustomView(element: element)
            NavigationLink(destination: DestinationView()), 
            label: {}).opacity(0)
        }
    }
}
List { 
    ForEach(elements) { element in
        ZStack {
            CustomView(element: element)
            NavigationLink(destination: DestinationView()) {
                EmptyView()
            }.opacity(0.0)
        }
    }
}

Setting .opacity(0) on the NavigationLink seems to be the most reliable solution for me because I noticed that it might show the indicators again when messing with the .listStyle property. You will also not lose the highlighted effect.

var body: some View {
    NavigationView {
        List {
            ForEach(items) { item in
                ZStack(alignment: .leading) {
                    NavigationLink(destination: EmptyView()) {
                        EmptyView()
                    }
                    .opacity(0)

                    Text(item.value)
                }
            }
        }
    }
}

This is what worked for me, just adding an empty NavigationLink in a ZStack

List(viewModel.items, id: \.id) { item in
    ZStack {
        NavigationLink(destination: Destination()) {}
        CustomView(item: item)
    }
}

Only this worked for me, when I tried to implement button tap inside row in List:

ZStack {
                NavigationLink(destination: FlightBoardInformation(flight: flight), tag: FlightBoardNavigation.toFlightDetailed, selection: $navigation) {
                    EmptyView()
                }
                .frame(width: 0, height: 0)
                .hidden()
                .disabled(true)
                Button(action: {
                        self.navigation = .toFlightDetailed
                }) {
                    Text("\(self.flight.airline) \(self.flight.number)")
                }.buttonStyle(PlainButtonStyle())
            }

Although .background(...).opacity(0) works, in a more complex view it expands itself through all the view and conflicts with other elements like buttons.

If you need it inside a List, what worked for me is also marking the NavigationLink as .disabled(true):

    Text(...)
      .background( NavigationLink(...).opacity(0).disabled(true) )

The best workaround for me is using background:

NavigationLink(...) {}
       .opacity(0)
       .background(
         HStack {
           Text("Your custom view without arrow")
         }
       ) 

Or if you need dynamic height as @turingtested posted use NavigationLink as background

Text("Your custom view without arrow")
        .background(NavigationLink( ... ) {}.opacity(0))

though there is lots of solution. I'm posting my one.

var body: some View {
    VStack{
        List{
            ForEach (items){item in
                switch item.onClick {
                    //For SettingsOverviewView
                case .Settings:
                    ZStack{
                        NavigationLink (destination: SettingsMenuView(item: item)){
                            EmptyView()
                        }
                        .opacity(0.0)
                        .buttonStyle(PlainButtonStyle())
                        
                        //some views that you will show as your listItem
                        HStack {
                           Text(item.name)
                              .font(.body)
                           Spacer()
                        }
                    }
                }
            }
            .listStyle(GroupedListStyle())
        }
    }
}

Use .background modifier.

ForEach(elements) { e in
  AnyViewYouWantToShow(e)
    .background(
      NavigationLink("", destination: DestinationView()))
        .opacity(0)
    )
}

A lot of examples playing around with ZStack and .opacity but for my opinion SwiftUI can offer more elegant solution using NavigationLink with isActive parameter that works perfect with .listRowSeparator or .listStyle modificators:

struct HidingNavArrowInList: View {
    
    let planets = ["Mars", "Sun", "Mercury", "Venus", "Jupiter", "Uranus", "Saturn", "Earth"]
    
    @State var selectedPlanet: String?
    @State var showDetailView = false
    
    var body: some View {
        NavigationView {
            List {
                ForEach(planets, id: \.self) { planet in
                    Text(planet)
                        .onTapGesture {
                            segue(planet: planet)
                        }
                }
            }
            .background(
                NavigationLink(isActive: $showDetailView, destination: {
                    if let unwrappedPlanet = selectedPlanet {
                        VStack {
                            Text("This is detail view of \(unwrappedPlanet)")
                        }
                    }
                }, label: {
                    EmptyView()
                })
            )
        }
    }
    
    private func segue(planet: String) {
        selectedPlanet = planet
        showDetailView.toggle()
    }
}

You can also do like: This worked for me,

@State var boolValue: Bool = false


                HStack {
                    Text("Your text")
                    Toggle(isOn: $boolValue){
                        Text("")
                    }
                    if boolValue {
                        NavigationLink(destination: DestinationView()) {
                            EmptyView()
                        }.frame(width: 0)
                    }
                }

It also works with any View (not only Text)

ZStack {
    Text("Some text")
    NavigationLink(destination: Text("Hello")) { 
            EmptyView()
    }.frame(width: 0)
}

I set the opacity of the navigationLink to zero and it work like a charm

NavigationLink(
    destination: Text("Destination"),
    label: {}
).opacity(0)
Related