Search code examples
swiftuiswiftui-navigationlinkswiftui-navigationstack

NavigationLink as a Button in a list


I have NavigationStack with a List. I would like a NavigationLink to only trigger when Image(systemName: "info.circle") is tapped. Anywhere I place the NavigationLink, the whole row acts as a link button to new view.

NavigationStack(path: $navigationPath) {
        List {
            ForEach(aircraftVM.aircraftCollect, id: \.id) { aircraft in
                    HStack{
                        VStack(alignment: .leading) {
                            Text(aircraft.registration ?? "")
                            Text(aircraft.type ?? "")
                                .font(.callout)
                                .foregroundStyle(.secondary)
                            Text(aircraft.aircraftRemarks ?? "")
                                .font(.footnote)
                                .foregroundStyle(.secondary)
                        }
                    
                        NavigationLink(value: aircraft) {
                            Image(systemName: "info.circle")
                        }
                    }
                
            }
            .onDelete(perform: delete)
        }
        
        .navigationDestination(for: AircraftEntity.self) { aircraft in
            AircraftDatabaseDetailView(aircraft: aircraft)
        }

Solution

  • I was curious and built out a working copy of your code. The key items are .buttonStyle(.borderless) and using a Button(action:,label:)

    import SwiftUI
    
    struct Aircraft : Hashable{
      var id = UUID()
      var type : String = "Boeing 747"
      var details : String = "In Service"
    }
    
    struct ContentView: View {
      
      @State var aircraftArray = [Aircraft]()
      @State var navigationPath = [Aircraft]()
      
      var body: some View {
        NavigationStack(path: $navigationPath) {
          if aircraftArray.count > 0 {
            List {
              ForEach(0..<10) { index in
                HStack{
                  VStack(alignment: .leading) {
                    Text(aircraftArray[index].id.uuidString.prefix(4))
                    Text(aircraftArray[index].type)
                      .font(.callout)
                      .foregroundStyle(.secondary)
                    Text(aircraftArray[index].details)
                      .font(.footnote)
                      .foregroundStyle(.secondary)
                  }
                  
                  Button {
                    navigationPath.append(aircraftArray[index])
                  } label: {
                    Image(systemName: "info.circle")
                  }
                }
              }
            }
            .buttonStyle(.borderless)
            .navigationDestination(for: Aircraft.self) { aircraft in
                AircraftDatabaseDetailView(aircraft: aircraft)
            }
          }
        }
        .onAppear {
          // Populate the aircraft array
          for _ in 0...10 {
            aircraftArray.append(Aircraft())
          }
        }
      }
      
      private func delete() {}
    }
    
    struct AircraftDatabaseDetailView: View {
      var aircraft : Aircraft
      var body: some View {
        VStack {
          Text(aircraft.id.uuidString.prefix(4))
          Text(aircraft.type)
          Text(aircraft.details)
        }
        .navigationBarTitleDisplayMode(.inline)
      }
    }