Reputation: 2394
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
Upvotes: 63
Views: 50943
Reputation: 11
I'm using SwiftUI with Xcode 15.4. Solution in 2024:
var body: some View {
NavigationView {
List(items){ item in
Section {
YourObjectView()
}
.listRowSeparator(.hidden) //Removing separator between cells
.background{ NavigationLink("", destination: SpecificView(url: "www.yourWebPage.com"))} //Added it as background so that the > (chevron) on the righ side and extra padding disappears
}
.navigationTitle("Your List Title")
.listStyle(.grouped) //Removes boundaries on sides of ListView
.scrollContentBackground(.hidden) //Removes Background on cells
}
}
Added a couple of extra functions that have helped me in my projects.
Upvotes: 0
Reputation: 196
Working for Swiftui swift 5, ios 17+
NavigationLink(destination: Destination()) {
Rectangle().opacity(0.0)
}
.opacity(0.0)
.opacity(0) do the job here, without this it will not work.
Upvotes: -2
Reputation: 560
Works for me on iOS 16/17
NavigationLink(destination: YourView) {
Color.clear // or EmptyView, etc.
}
.foregroundStyle(Color.clear)
.opacity(0)
also works but in my case I needed .foregroundStyle(Color.clear)
For some reason with .opacity(0)
the NavigationLink
is not working if I put it outside of the ListView
.
Upvotes: 2
Reputation: 955
To hide the navigation link forward arrow icon we have to do the following steps.
Here is the code -
List($store.models, id: \.id) { model in
CustomListItem(model: model.wrappedValue)
.overlay {
NavigationLink {
DetailView()
} label: {
EmptyView()
}
.opacity(0) //this will hide the arrow icon.
}
.listRowSeparator(.hidden)
}
.listStyle(.plain)
Upvotes: 0
Reputation: 1
In my case, foregroundColor modifier works for me.
NavigationLink(EmptyView(), label: {
//place your custom view
Text("your Label")
}).buttonStyle(PlainButtonStyle()).foregroundColor(Color.clear)
Upvotes: 0
Reputation: 7154
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.
Bonus: Using .overlay
modifier works too!
Upvotes: 76
Reputation: 87
2023 Update
This simple solution works for me:
ZStack {
CustomCell()
NavigationLink(destination: DetailView()) {
EmptyView()
}
.opacity(0)
}
Upvotes: 2
Reputation: 86
I've also struggled with this recently and I think I've found a solution by using a custom view for the navigation link (it works for me):
struct CustomNavigationLink<D: View, L: View>: View {
@ViewBuilder var destination: () -> D
@ViewBuilder var label: () -> L
@State private var isActive = false
var body: some View {
Button {
withAnimation {
isActive = true
}
} label: {
label()
}
.onAppear {
isActive = false
}
.overlay {
NavigationLink(isActive: $isActive) {
destination()
} label: {
EmptyView()
}
.opacity(0)
}
}
}
And you use like this:
CustomNavigationLink {
SomeViewHere()
} label: {
Text("hello world")
}
Upvotes: 5
Reputation: 2792
Finally found out a way how to avoid the the chevron without doing some tricky ZStacks
and other solutions. The only downside is that this is only tested on iOS 16 with the new NavigationPath
+ NavigationStack
.
Instead of using a regular NavigationLink
where you apply the hashable
object, you'll just use a regular Button
and append the object to the NavigationPath
.
@State private var path = NavigationPath()
var body: some View {
List {
ForEach(viewModel.customers) { customer in
Button {
path.append(customer)
} label: {
CustomerCell(customer: customer)
}
}
}
.navigationDestination(for: Customer.self) { customer in
CustomerView(customer: customer)
}
}
For projects using the NavigationBackport (for preparing the new navigation), it might work as well. As you can use NBNavigationPath
and append the object to the path with a Button
just like the example above.
Upvotes: 8
Reputation: 930
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()
}
}
Upvotes: 0
Reputation: 10393
Use .background
modifier.
ForEach(elements) { e in
AnyViewYouWantToShow(e)
.background(
NavigationLink("", destination: DestinationView()))
.opacity(0)
)
}
Upvotes: 1
Reputation: 1794
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)
}
}
}
}
}
Upvotes: 3
Reputation: 746
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())
}
}
}
Upvotes: 0
Reputation: 1356
I set the opacity
of the navigationLink
to zero and it work like a charm
NavigationLink(
destination: Text("Destination"),
label: {}
).opacity(0)
Upvotes: -2
Reputation: 149
List {
ForEach(elements) { element in
ZStack {
CustomView(element: element)
NavigationLink(destination: DestinationView()) {
EmptyView()
}.opacity(0.0)
}
}
}
Upvotes: 7
Reputation: 13
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) )
Upvotes: 1
Reputation: 3708
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))
Upvotes: 1
Reputation: 121
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())
}
Upvotes: 1
Reputation: 1414
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)
}
}
Upvotes: 3
Reputation: 1475
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)
}
}
}
Upvotes: 9
Reputation: 1128
I got it done with this
NavigationLink(destination: DestinationView()) {
EmptyView()
}
.frame(width: 0, height: 0)
.hidden()
Upvotes: 23
Reputation: 1
It also works with any View (not only Text)
ZStack {
Text("Some text")
NavigationLink(destination: Text("Hello")) {
EmptyView()
}.frame(width: 0)
}
Upvotes: -2
Reputation: 1
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)
}
}
Upvotes: -1
Reputation: 1152
The way it worked for me:
List {
ForEach(elements) { element in
ZStack {
CustomView(element: element)
NavigationLink(destination: DestinationView()) {
EmptyView()
}.buttonStyle(PlainButtonStyle())
}
}
}
Upvotes: 46
Reputation: 259
@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 }
}
}
Upvotes: 3