0

I'm trying to have a multi-view workflow in SwiftUI where you can start back where you left off, yet still have nice transitions of NavigationView.

As a basic example, I want it to have SignupView (where you enter user credentials) > PersonalInfoView (where you enter other personal info) > etc.

I initially went with a simple NavigationLink from one step to the next. But I also want it so that if you complete the SignupView and then quit the app, if you open it again, the user can be brought to PersonalInfoView directly. As in, you can start back where you left off.

So I thought of using conditional rendering:

if !userExists { 
  SignupView() 
} else if !hasPersonalInfo {
  PersonalInfoView()
} else {
  Text("Signup complete")
}

But now whenever I go from SignupView to PersonalInfoView I don't get the nice sliding transition that I would if I were using a NavigationLink. And if I add a NavigationLink to go to PersonalInfoView, it will slide into it (like a typical navigation) then slide out into the the other version of the view (the conditional rendering one).

So I guess my question is, what's the best way to handle conditional views all the while remaining in the whole NavigationView paradigm. Thanks

EDIT: I might not have explained my issue well enough: I still want to use NavigationView for everything (in order to have the transitions, back button, etc). I just want to be able to start at different points in the process but for every view following that to be part of the navigation stack.

Pandawan
  • 117
  • 3
  • 11

1 Answers1

3

You can explicitly apply transitions to the views:

if !userExists { 
  SignupView()
    .transition(.slide)
} else if !hasPersonalInfo {
  PersonalInfoView()
    .transition(.opacity)
} else {
  Text("Signup complete")
    .transition(.slide)
}

Also, for some transitions you may need to set the userExists inside the withAnimation block:

withAnimation {
    userExists = true
}

EDIT

Here is an updated version (assuming that userExists and hasPersonalInfo are persisted (eg. stored in UserDefaults):

struct ContentView: View {
    var userExists = true
    var hasPersonalInfo = false

    var body: some View {
        NavigationView {
            VStack {
                if !userExists {
                    SignupView()
                } else if !hasPersonalInfo {
                    PersonalInfoView()
                } else {
                    Text("Signup complete")
                }
            }
        }
    }
}
struct SignupView: View {
    @State private var isLinkActive = false

    var body: some View {
        VStack {
            Text("SignupView")
            Button("Go to PersonalInfoView") {
                self.isLinkActive = true
            }
            .background(NavigationLink(destination: PersonalInfoView(), isActive: $isLinkActive) { EmptyView() }.hidden())
        }
    }
}
struct PersonalInfoView: View {
    @State private var isLinkActive = false

    var body: some View {
        VStack {
            Text("PersonalInfoView")
            Button("Go to MainView") {
                self.isLinkActive = true
            }
            .background(NavigationLink(destination: Text("Signup complete"), isActive: $isLinkActive) { EmptyView() }.hidden())
        }
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209
  • Hmm, this does not seem to work. [Here's a video of it](https://imgur.com/DXMUt3h) I also tried adding `.animation()` and moving the `.transition()` to the NavigationView, but to no avail. – Pandawan Sep 10 '20 at 22:16
  • 1
    @PandawanFr Try wrapping your code in a VStack and only then in a NavigationView. – pawello2222 Sep 10 '20 at 22:17
  • Wrapping in a VStack does seem to animate but it is not the same behavior as the NavigationLink, there is no back button (tho I guess I can fake that), and the animation is not the same. I've added [a couple of videos to show the differences](https://imgur.com/a/snvpbiJ). I might not have explained my issue well enough: I still want to use NavigationView for everything, I just want to be able to start at different points in the process but for every view following that to be part of the navigation stack. – Pandawan Sep 10 '20 at 22:43
  • @PandawanFr Yes, it wasn't clear enough. I updated my answer with more examples. – pawello2222 Sep 10 '20 at 23:19
  • This just gives me links to navigate to those views. Sorry if I'm explaining myself poorly. What I'm looking for is: From cold start, the app should navigate to whichever view I need (like I do in the conditional). On the other hand, if I'm already in the app, I want it to flow like a regular navigation stack, where pressing on a NavigationLink moves from one view to the next (without having the conditional change the view and therefore lose the navigation stack). – Pandawan Sep 11 '20 at 00:04
  • @PandawanFr I'm sorry but I don't understand you - you described the first scenario, yet you want to have a NavigationLink with a back arrow. If you have a NavigationView then all your child views are part of the same NavigationStack (until you present a sheet) and you can use NavigationLink in these views any way you like. – pawello2222 Sep 11 '20 at 08:12
  • Sorry, let me try to explain again. I want the typical NavigationView with NavigationLinks that go from one view to the next, adding them onto the navigation stack (basic stuff). Now the hard part that I’m trying to figure out: I want it so that, when the user restarts the app, he can start back to whichever view he was on before he quit and continue in the basic navigation stack flow. Using conditionals was just an idea I had of rendering different views based on conditions, but it doesn’t allow for typical navigation stack behavior. – Pandawan Sep 11 '20 at 16:29
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/221336/discussion-between-pawello2222-and-pandawanfr). – pawello2222 Sep 11 '20 at 16:49