Ad

How To Use NavigationLink For List View Swipe Action

- 1 answer

I'm wondering how to place NavigationLink into swipeActions section in code below. Code itself is compiled without any issue but when I tap "Edit" link nothing happens. My intention is to show another view by tapping "Edit". Thanks

var body: some View {
    List {
        ForEach(processes, id: \.id) { process in
            NavigationLink(process.name!, destination: MeasurementsView(procID: process.id!, procName: process.name!))
                .swipeActions() {
                    Button("Delete") {
                        deleteProcess = true
                    }.tint(.red)
                    NavigationLink("Edit", destination: ProcessView(procID: process.id!, procName: process.name!)).tint(.blue)
                }
        }
    }
}
Ad

Answer

It does not work because swipeActions context is out of NavigationView. Instead we can use same NavigationLink for conditional navigation, depending on action.

Here is a simplified demo of possible approach - make destination conditional and use programmatic activation of link.

Tested with Xcode 13.2 / iOS 15.2

demo

struct ContentView: View {
    var body: some View {
        NavigationView {
            List {
                ForEach(0..<2, id: \.id) {
                    // separate into standalone view for better
                    // state management
                    ProcessRowView(process: $0)
                }
            }
        }
    }
}

struct ProcessRowView: View {
    enum Action {
        case view
        case edit
    }
    @State private var isActive = false
    @State private var action: Action?
    let process: Int

    var body: some View {
        // by default navigate as-is
        NavigationLink("Item: \(process)", destination: destination, isActive: $isActive)
            .swipeActions() {
                Button("Delete") {

                }.tint(.red)
                Button("Edit") {
                    action = .edit    // specific action
                    isActive = true   // activate link programmatically
                }.tint(.blue)
            }
            .onChange(of: isActive) {
                if !$0 {
                    action = nil  // reset back
                }
            }
    }

    @ViewBuilder
    private var destination: some View {
        // construct destination depending on action
        if case .edit = action {
            Text("ProcessView")
        } else {
            // just to demo different type destinations
            Color.yellow.overlay(Text("MeasurementsView"))
        }
    }
}
Ad
source: stackoverflow.com
Ad