How can you switch views without having a navigationView or an popover?

Viewed 17959

I am trying to change a view without having something over it like when you used segue in swift. But the only solution I came up with is to have a navigation bar navigationBar or a popover.

struct view1: View {

    var body: some View{

        Button(action: {
//          go to view2``
        }) {
            Text("press")
        }

    }
}
struct view2: View {

    var body: some View{
       Text("yeay")

    }
}
4 Answers

If you just want to hide the navigation bar it's easy:

import SwiftUI

struct View2: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    var body: some View {
        VStack {
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }) {
                Text("POP")
            }
        }
        .navigationBarTitle("")
        .navigationBarBackButtonHidden(true)
        .navigationBarHidden(true)
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: View2()) {
                Text("PUSH")
                    .navigationBarTitle("")
                    .navigationBarHidden(true)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

If you, instead, want to get rid of the NavigationView and NavigationLink views you have to implement your own custom navigation. It's a little more complicated. The following is just a simple example of a push/pop transition between two views.

import SwiftUI

struct View2: View {
    @Binding var push: Bool

    var body: some View {
        ZStack {
            Color.yellow
            Button(action: {
                withAnimation(.easeOut(duration: 0.3)) {
                    self.push.toggle()
                }
            }) {
                Text("POP")
            }
        }
        .edgesIgnoringSafeArea(.all)
    }
}

struct View1: View {
    @Binding var push: Bool

    var body: some View {
        ZStack {
            Color.green
            Button(action: {
                withAnimation(.easeOut(duration: 0.3)) {
                    self.push.toggle()
                }
            }) {
                Text("PUSH")
            }
        }
        .edgesIgnoringSafeArea(.all)
    }
}

struct ContentView: View {
    @State private var push = false

    var body: some View {
        ZStack {
            if !push {
                View1(push: $push)
                    .transition(.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .leading)))
            }

            if push {
                View2(push: $push)
                    .transition(.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .trailing)))
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
} 

Anyone coming to this later might find this to be of interest; in short, shove a hunk of data into @environment, tickle that with a button push in whatever view you want, and since it's at the very top of the overall application stack, it forces a redraw, which acts like a full view navigation, without the potential lost memory and orphaned or lost objects of the whole push/pop navigation view silliness.

It's still a little more "single page app"-ey than I'd like, but since SwiftUI is so crippled in its navigation thoroughness, it'll do nicely.

Not my site, not my link, not my tutorial, and it's buried way down in the list of hits when searching, which is a shame; this is the closest to what many are looking for. IMO, this should be baked into SwiftUI as a first class operation, and made less workaround-ey.

https://blckbirds.com/post/how-to-navigate-between-views-in-swiftui-by-using-an-environmentobject/

You can also do this completely without NavigationView. Take a look at the following example:

struct MainView: View
{
    @State private var showView = "LoginView"
    
    var body: some View
    {
        switch showView
        {
        case "LoginView":
            Text("Please login.")
            Button("Login")
            {
                showView = "NormalView"
            }
        case "NormalView":
            Text("This is youre NormalView!")
            Button("Next view")
            {
                showView = "NextView"
            }
        case "NextView":
            Text("This is the NextView")
            Button("Back")
            {
                showView = "NormalView"
            }
        default:
            Text("Default") // you should never reach this
        }
    }
}

Perhaps not the best code practice, but it solves your problem.

I think this not best way but it's easy

struct ContentView: View {

@State var gotoDetail3:Bool = false

var body: some View {
    NavigationView{
        ZStack{
            VStack {
                // Normal NavigationLink
                NavigationLink {
                    Text("Detail......")
                } label: {
                    Text("goto..")
                }
                
                //use for change state
                Button {
                    gotoDetail3.toggle()
                } label: {
                    Text("goto33333")
                }
            }// End VStack
            
            
            // Hide Navigation Link
            NavigationLink(
                LocalizedStringKey("123"), destination: Text("Subsequent View"),
                isActive: $gotoDetail3)
                .hidden()
        }
        
    }
}
    
}
Related