12

I would like to add an extra function to the NavigationLink.

example code is something like this:

struct ContentView: View {

func yes () {
print("yes")
}

var body: some View {

NavigationView {
NavigationLink(destination: level1()) {

     Text("Next")      
}}}}

I know this doesn't work, but is it possible to do something like this? (It will go to the destination and call the function at the same time)

NavigationLink(destination: level1(), yes()) {Text("Next")}   

I tried putting a button inside the NavigationLink but it didn't work either. When I do this only the function in the button works, NavigationLink doesn't.

NavigationLink(destination: level1())   {
        Button(action: { self.yes() }) 
        { Text("Button")}
        }
I Kaya
  • 417
  • 5
  • 22

2 Answers2

30

Use the onAppear(perform:). This will perform some function on a View's appear.

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: DetailView().onAppear {
                self.someFunc()
            }) {
                Text("First Screen")
            }
        }
    }

    func someFunc() {
        print("Click")
    }
}

struct DetailView: View {
    var body: some View {
        Text("Second Screen")
    }
}

Aleksey Potapov
  • 3,683
  • 5
  • 42
  • 65
  • You're right, I can use onAppear in NavigationLink and the DetailView anyway. Thanks! – I Kaya Mar 05 '20 at 16:58
  • 1
    the .onAppear on the NavigationLink is spot on. This is a simple solution to many other overly complex solutions proposed out there to perform and action on a View. In a way sort of a way to get a viewdidappear under Swift. – David Jan 28 '21 at 19:10
  • in iOS 15 I get glitches - navigation view programmatically taps back button and reorders list elements. I cannot recommend the solution – SevenDays Nov 19 '21 at 21:31
  • @SevenDays Might be. This solution was for iOS 13 originally. Please let me know, which way would be better for iOS 15? – Aleksey Potapov Nov 23 '21 at 21:30
  • @AlekseyPotapov I posted a solution to this question. – SevenDays Nov 24 '21 at 16:10
1

Solution for SwiftUI, iOS 15.1 & Xcode 13.1.

import Foundation
import SwiftUI

// NavigationLink replacement with action
// Usage:
//var body: some View {
//    NavigationButton(
//        action: { print("tapped!") },
//        destination: { Text("Pushed View") },
//        label: { Text("Tap me") }
//    )
//}

struct NavigationButton<Destination: View, Label: View>: View {
    var action: () -> Void = { }
    var destination: () -> Destination
    var label: () -> Label
    
    @State private var isActive: Bool = false
    
    var body: some View {
        Button(action: {
            self.action()
            self.isActive.toggle()
        }) {
            self.label()
                .background(
                    ScrollView { // Fixes a bug where the navigation bar may become hidden on the pushed view
                        NavigationLink(destination: LazyDestination { self.destination() },
                                       isActive: self.$isActive) { EmptyView() }
                    }
                )
        }
    }
}

// This view lets us avoid instantiating our Destination before it has been pushed.
struct LazyDestination<Destination: View>: View {
    var destination: () -> Destination
    var body: some View {
        self.destination()
    }
}

I cannot find the original code, but this solution worked for me perfectly.

Jan
  • 1,032
  • 11
  • 26
SevenDays
  • 3,718
  • 10
  • 44
  • 71