NavigationView and NavigationLink on button click in SwiftUI? NavigationView and NavigationLink on button click in SwiftUI? swift swift

NavigationView and NavigationLink on button click in SwiftUI?


To fix your issue you need to bind and manage tag with NavigationLink, So create one state inside you view as follow, just add above body.

@State var selection: Int? = nil

Then update your button code as follow to add NavigationLink

NavigationLink(destination: Text("Test"), tag: 1, selection: $selection) {    Button(action: {        print("login tapped")        self.selection = 1    }) {        HStack {            Spacer()            Text("Login").foregroundColor(Color.white).bold()            Spacer()        }    }    .accentColor(Color.black)    .padding()    .background(Color(UIColor.darkGray))    .cornerRadius(4.0)    .padding(Edge.Set.vertical, 20)}

Meaning is, when selection and NavigationLink tag value will match then navigation will be occurs.

I hope this will help you.


The accepted answer uses NavigationLink(destination:tag:selection:) which is correct.

However, for a simple view with just one NavigationLink you can use a simpler variant: NavigationLink(destination:isActive:)


Usage #1

NavigationLink is activated by a standard Button:

struct ContentView: View {    @State var isLinkActive = false    var body: some View {        NavigationView {            VStack(alignment: .leading) {                ...                NavigationLink(destination: Text("OtherView"), isActive: $isLinkActive) {                    Button(action: {                        self.isLinkActive = true                    }) {                        Text("Login")                    }                }            }            .navigationBarTitle(Text("Login"))        }    }}

Usage #2

NavigationLink is hidden and activated by a standard Button:

struct ContentView: View {    @State var isLinkActive = false    var body: some View {        NavigationView {            VStack(alignment: .leading) {                ...                Button(action: {                    self.isLinkActive = true                }) {                    Text("Login")                }            }            .navigationBarTitle(Text("Login"))            .background(                NavigationLink(destination: Text("OtherView"), isActive: $isLinkActive) {                    EmptyView()                }                .hidden()            )        }    }}

Usage #3

NavigationLink is hidden and activated programmatically:

struct ContentView: View {    @State var isLinkActive = false    var body: some View {        NavigationView {            VStack(alignment: .leading) {                ...            }            .navigationBarTitle(Text("Login"))            .background(                NavigationLink(destination: Text("OtherView"), isActive: $isLinkActive) {                    EmptyView()                }                .hidden()            )        }        .onAppear {            self.isLinkActive = true        }    }}

Here is a GitHub repository with different SwiftUI extensions that makes navigation easier.


Another approach:

SceneDelegate

if let windowScene = scene as? UIWindowScene {            let window = UIWindow(windowScene: windowScene)            window.rootViewController = UIHostingController(rootView: BaseView().environmentObject(ViewRouter()))            self.window = window            window.makeKeyAndVisible()        }

BaseView

import SwiftUIstruct BaseView : View {    @EnvironmentObject var viewRouter: ViewRouter    var body: some View {        VStack {            if viewRouter.currentPage == "view1" {                FirstView()            } else if viewRouter.currentPage == "view2" {                SecondView()                    .transition(.scale)            }        }    }}#if DEBUGstruct MotherView_Previews : PreviewProvider {    static var previews: some View {        BaseView().environmentObject(ViewRouter())    }}#endif

ViewRouter

import Foundationimport Combineimport SwiftUIclass ViewRouter: ObservableObject {    let objectWillChange = PassthroughSubject<ViewRouter,Never>()    var currentPage: String = "view1" {        didSet {            withAnimation() {                objectWillChange.send(self)            }        }    }}

FirstView

import SwiftUIstruct FirstView : View {    @EnvironmentObject var viewRouter: ViewRouter    var body: some View {        VStack {            Button(action: {self.viewRouter.currentPage = "view2"}) {                NextButtonContent()            }        }    }}#if DEBUGstruct FirstView_Previews : PreviewProvider {    static var previews: some View {        FirstView().environmentObject(ViewRouter())    }}#endifstruct NextButtonContent : View {    var body: some View {        return Text("Next")            .foregroundColor(.white)            .frame(width: 200, height: 50)            .background(Color.blue)            .cornerRadius(15)            .padding(.top, 50)    }}

SecondView

import SwiftUIstruct SecondView : View {    @EnvironmentObject var viewRouter: ViewRouter    var body: some View {        VStack {            Spacer(minLength: 50.0)            Button(action: {self.viewRouter.currentPage = "view1"}) {                BackButtonContent()            }        }    }}#if DEBUGstruct SecondView_Previews : PreviewProvider {    static var previews: some View {        SecondView().environmentObject(ViewRouter())    }}#endifstruct BackButtonContent : View {    var body: some View {        return Text("Back")            .foregroundColor(.white)            .frame(width: 200, height: 50)            .background(Color.blue)            .cornerRadius(15)            .padding(.top, 50)    }}

Hope this helps!