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!