Is there a cleaner solution different by this answer and this answerto remove those chevrons on lists? Maybe today apple improved it (even not using navigationStack) the kind of issue.
I know there is same question, but is relatively a bit old, and I'm wondering if there is a better solution today, still not using navigation stack. the first given solution seems to be a bit slow respect standard code, and a bit too verbose.
my starting code
import SwiftUI
struct FakeCar: Identifiable, Hashable {
let id = UUID().uuidString
let name: String
}
struct DevelopingView: View {
let test: [FakeCar] = [
FakeCar(name: "car 1"),
FakeCar(name: "car 2")
]
@State private var tappedItem: FakeCar?
var body: some View {
NavigationView {
List {
//standard code with chevron, I do not want it.
Section (header: Text("Base")) {
ForEach(test) { item in
NavigationLink(destination: Text("destination: \(item.name)") ) {
Text(item.name)
}
}
}
//solution from apple site, but adding vstack elements are not "centered" vertically due to navigation link
//✅ SOLUTION this version is upgraded by me, I needed to remove the default chevron, adding VStack with its options, and opacity and frame to empty navigtionLink
Section (header: Text("test 1 - ✅ solution")) {
ForEach(test) { item in
ZStack {
VStack(alignment: .leading, spacing: 0) {
NavigationLink(destination: Text("destination: \(item.name)")) { EmptyView() }
.opacity(0.0)
.frame(height:0)
Text(item.name)
}
}
}
}
Section (header: Text("test 1.1 - ✅✅ better solution")) {
ForEach(test, id: \.self) { item in
ZStack(alignment: .leading) {
NavigationLink(destination: Text("destination: \(item.name)")) {
EmptyView()
}
.opacity(0)
Text(item.name)
}
}
}
//another solution i tested, but elements are "centered" and do not know how to adjust it
Section (header: Text("test 2")) {
ForEach(test, id: \.self) { item in
ZStack {
NavigationLink(destination: Text("destination: \(item.name)")) {
EmptyView()
}
.opacity(0)
.buttonStyle(PlainButtonStyle())
Text(item.name)
}
}
}
}
}
//solution found on stack, works, but is a bit verbose and unclear
NavigationView{
List{
ForEach(test) { item in
Button(action: { tappedItem = item }) { // << activate !!
Text("Select: \(item.name)")
.padding(.vertical,3)
}
}
}
.background(
NavigationLink(destination: Text("MessageDetailView \(tappedItem?.name ?? "N/D")"),
isActive: Binding(
get: { tappedItem != nil }, // << handle !!
set: { _,_ in tappedItem = nil }
)){
EmptyView()
}
)
}
}
}
//gives Identifiable tho stringgs
extension String: Identifiable {
public typealias ID = Int
public var id: Int {
return hash
}
}
SOLUTION based on the Sweeper answer, adding empty view, opacity and alignment
NavigationView {
List {
Section(header: Text("Available")) {
if classFromEntryPoint.availableApps.isEmpty {
Text("No app Available")
} else {
ForEach(classFromEntryPoint.availableApps) { app in
ZStack(alignment: .leading) {
VStack(alignment: .leading, spacing: 0) {
NavigationLink(destination: StoreAppDetailView(selectedApp: app)) { EmptyView() }
.opacity(0.0)
RowCell(app: app)
}
}
}
}
}
}
}
In iOS 17, you can use navigationDestination(item:destination:)
to bind the navigation destination to a variable. That means you can just have Button
s in your list, setting the variable to different values.
@State var tappedItem: FakeCar? = nil
NavigationStack { // this does not work with the old NavigationView!
List {
Section {
ForEach(test) { item in
Button {
self.tappedItem = item
} label: {
Text(item.name)
}
.tint(.black)
}
}
}
.navigationDestination(item: $tappedItem) { item in
Text("destination: \(item.name)")
}
}
That said, this becomes rather cumbersome when you have multiple types of data (not just FakeCar
s). You might need an enum with associated values, and switch on it in navigationDestination
to compute what destination it should be.
As for the solution with the ZStack
, you just need to say alignment: .leading
for the alignment to work:
ZStack(alignment: .leading) {
NavigationLink(destination: Text("destination: \(item.name)")) {
EmptyView()
}
.opacity(0)
Text(item.name)
}