UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

DAY 60 - Reset navigation history

Forums > 100 Days of SwiftUI

I just finished the DAY 60 challenge and implemented all options. So I read the data from the JSON, I decode this into a User struct and I even attach an array (Class) of the User items through the environment Binding so that the array is available in all other screens.

I do have one issue where I hope someone could give me a direction for so that I can dive deeper into that.

My navigation is as follows: ContentView -> DetailView -> FriendsList -> DetailView

Everything works fine ( so I am pretty proud on myself :P), the only thing I don't like is the "DetailView -> FriendsList -> DetailView" navigation... because you could open 40x another user by clicking through the friends list... but when you then want to go back to the home screen you have to click back 40 times... is there a better way to implement this kind of navigation?

3      

I also need help with this. We decided to do away with NavigationView in our app completely because of this and simply made it a single page app with inner components changing using @State variables and multiple modals.

3      

what about adding a button to navigation bar to take user back to content screen or tab bar

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Hi NigelGee, Thanks for your answer. I thought about that as well but then I was wondering how?

First of all I couldn't think of a way how you can navigatie in code? I tried adding a navigation link into the struct hierarchy with as label "" (to make it hidden) and an isActive property attached to a @State Boolean property which got toggled in the navigation item button's action. This does do the trick of navigating but that does sound like a very nasty solution to me?

And besides the 'how you can navigate in code', how DO you actually navigate to another view because when I use the navigation link approach above and navigate to "ContentView()" then it still leaves the back button on the screen?

3      

Hi Nico, Navigating to and back from another view in code is nicely explained in the article Navigation in SwiftUI.

4      

Hi @baduxdaniel,

thanks for your reply, it is indeed an interesting link but my problem remains... I added a trailing navigation bar item with the following code:

.navigationBarItems(trailing: NavigationLink(destination: ContentView()) {
            Image(systemName: "house.fill")
            .padding()
        })

This does indeed work, however, clicking on the 'Home' button shows a navigation animation to the right (as if you navigate further). Besides that it also still shows an back button which shouldn't be the case since it is the 'start' page. And it even gets worse because if you then open another item again you get two navigation items above each other (see linked images)...

So am I doing something wrong here or is it prossible to navigate without keeping the history?

I tried sharing an image above but now sure how it works so I also attach a link to the screen I get to make it more clear:

https://noki.stackstorage.com/s/lNDL1U26Q1q5nOs https://noki.stackstorage.com/s/4TixyabvK5qCMok

3      

Hi @Nicoliden,

the post dates a little but I got to this same point today, and made the same remark when I finished this app.

My opinion: unless I missed something, so far nothing has taught us in the course to do this for now. I obviously hope that it will be in the rest of the course, but for the moment this is not the case on day 60. There is certainly a way to completely bypass the navigationView to manage "manually" the navigation between views (if someone here can confirm it and reassure me thank you), and I am in a hurry to discover this kind of technique to make me a "home made" navigation.

3      

Sorry about my previous answer as I miss understood what you want and it in "Swift" called

_ = navigationController?.popToRootViewController(animated: true)

however I am currently looking for an answer to it too.

https://www.hackingwithswift.com/forums/swiftui/like-to-poptorootviewcontroller-swift-however-do-not-seem-to-the-same-in-swiftui/966

if I get an answer make sure that it posted here too.

3      

i posted a code snippet on stackoverflow this week which might be helpful here.

With that approach you can go back to the main view from every other view and start without a back button.

https://stackoverflow.com/questions/61367716/swiftui-navigationview-getting-back-only-from-second-screen-and-not-from-the-nex/61372911#61372911

3      

I got this to work more or less, but the solution isn't great. I created an ObservableObject model and had it hold an activeUser published property. Then, instead of "real" NavigationLinks I use a Button in my list which sets the model's activeUser to a user. In order to have this actually navigate, I put a single NavigationLink before my List in ContentView, with a custom binding:

var body: some View {
        let showingDetail = Binding(get: {
            self.model.activeUser != nil
        }, set: { newValue in
            if !newValue {
                self.model.activeUser = nil
            }
        })

        return NavigationView {
            Group {
                NavigationLink(destination: UserDetailView(model: self.model), isActive: showingDetail) {
                    EmptyView()
                }
                List { /* ... */ }

This is doing what I want, as in, my navigation stack only ever has ContentView and UserDetailView. This isn't ideal, however, because of the way that views are getting redrawn. When I navigate back from a UserDetailView, the binding sets the model's activeUser to nil, and then for some unexplained reason, after it's already drawn the ContentView again, it then draws UserDetailView again...which it shouldn't! So I had to pull data in a junky way in UserDetailView:

    var user: User {
        if let user = model.activeUser {
            return user
        } else {
            // avoid random crashes while we're on ContentView
            return model.users.randomElement()!
        }
    }

This is doing exactly what I want, but I cannot explain why this user-fetching code is getting called over in UserDetailView while ContentView is view being displayed...

3      

Ok last week's WWDC was very interesting, I did not hear anything about navigation but I did find a workarround which works (maybe worked on iOS13 as well). I just wanted to check with you guys and girls if this is something which is fine to use or if it is just a hack which you should not use.

In the new @main swift file definition you could create a @StateObject definition for an appConfig so that it is available on all views. In this appConfig you can add (if necessary among other properties) a "selectedView" property, then in the Windowgroup you can use a switch on that property and when you navigate to a different view you simply update this property to the view you need.

It does seem to do exactly what I need but I just wonder if it is "ok" to use code like this?

class AppConfig: ObservableObject {
    @Published var selectedView = "Main"
}

@main
struct MyApp: App {
    @StateObject var game = Game()

    var body: some Scene {
        WindowGroup {
            switch game.selectedView {
                case "Welcome":
                    WelcomeView().environmentObject(game)
                case "Menu":
                    MenuView().environmentObject(game)
                case "Practice":
                    PracticeView().environmentObject(game)
                case "GameMode":
                    GameMode().environmentObject(game)
                case "Results":
                    ResultView().environmentObject(game)                    
                default:
                    Text("Something Else")
                }
        }
    }
}

At least it does seem to work for me, I now use this approach to show either a welcome screen or a menu and within the menuView I can navigate to three parts of the app (practice, game or results). Inside each of those three parts of the app (reachable through the menu) I use the navigationView so that I can navigate back and forward there but at any time I can switch back to my menu by simply updating "game.selectedView" back to "Menu".

I do get the following warning though but I found some blogs online of other people getting the same error on a simple navigation link (so don't know if it is beta related).

Attempting -[UIContextMenuInteraction dismissMenu], when not in an active state. This is a client error most often caused by calling dismiss more than once during a given lifecycle.

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.