Dawy
Dawy

Reputation: 946

How to use NavigationLink for List view swipe action

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)
                }
        }
    }
}

Upvotes: 4

Views: 3160

Answers (1)

Asperi
Asperi

Reputation: 258443

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"))
        }
    }
}

Upvotes: 10

Related Questions