SwiftUI – NavigationStack

By | 25/01/2023

In this post, we will see how to use the new NavigationStack that has substituted the old NavigationView.

We start creating an iOS project and then, we add three Swift files called User, Core and UserType.
The first one is our Model, the second one is the Business layer and finally UserType is the UI:

[USER.SWIFT]

import Foundation

// The Hashable is a protocol that provides a hashValue to the object.
// The hashValue is used to compare two instances.
struct User: Identifiable, Hashable {
    let id = UUID()
    var name: String
    var typeuser: TypeUser
}


enum TypeUser {
    case A
    case B
    case C
    
    var description: String {
        switch self {
        case .A: return "A"
        case .B: return "B"
        case .C: return "C"
        }
    }
}


[CORE.SWIFT]

import Foundation

class Core {
    
    func GetAllUsers() -> [User] {
        var result = [User]()
        
        result.append(User(name: "John", typeuser: TypeUser.A))
        result.append(User(name: "Neil", typeuser: TypeUser.B))
        result.append(User(name: "Sally", typeuser: TypeUser.C))
        
        return result
    }
}


[USERTYPE.SWIFT]

import SwiftUI

struct UserType: View {
    let name:String
    let typeuser: TypeUser
    var body: some View {
        VStack{
            HStack{
                Text("Hello \(name)")
                Text("Your type is \(typeuser.description)")
            }
        }
    }
}

struct UserType_Previews: PreviewProvider {
    static var previews: some View {
        UserType(name: "TestName", typeuser: TypeUser.A)
    }
}


Now, we modify the file ContentView to show a User list using NavigationStack:
[CONTENTVIEW.SWIFT]

import SwiftUI

struct ContentView: View {
    let lstUser = Core().GetAllUsers()
    var body: some View {
        NavigationStack{
            List(lstUser) { user in
                NavigationLink("User: \(user.name)"){
                    UserType(name: user.name, typeuser: user.typeuser)
                }
            }
            .navigationTitle("Users list")
        }
        
    }
}

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


If we run the application, these will the results:

We can see that everything works fine but, nothing changed compare to the old NavigationView.
This is true but, in reality, there are some new features introduced with NavigationStack and, one of these, is the navigationDestination that allow us to create dynamic routes.
Let’s see an example.
We add other three views called UserTypeA, UserTypeB and UserTypeC:
[USERTYPEA.SWIFT]

import SwiftUI

struct UserTypeA: View {
    let name:String
    let typeuser: TypeUser
    var body: some View {
        ZStack {
            // Definition background color
            Color.yellow.edgesIgnoringSafeArea(.all)
            VStack{
                Text("Hello \(name)")
                Text("Your type is \(typeuser.description)")
            }
            .bold()
            .foregroundColor(.black)
            .font(.system(size: 30))
        }
    }
}

struct UserTypeA_Previews: PreviewProvider {
    static var previews: some View {
        UserTypeA(name: "TestName", typeuser: TypeUser.A)
    }
}


[USERTYPEB.SWIFT]

import SwiftUI

struct UserTypeB: View {
    let name:String
    let typeuser: TypeUser
    var body: some View {
        ZStack {
            // Definition background color
            Color.green.edgesIgnoringSafeArea(.all)
            VStack{
                Text("Hello \(name)")
                Text("Your type is \(typeuser.description)")
            }
            .bold()
            .foregroundColor(.black)
            .font(.system(size: 30))
        }
    }
}

struct UserTypeB_Previews: PreviewProvider {
    static var previews: some View {
        UserTypeB(name: "TestName", typeuser: TypeUser.B)
    }
}


[USERTYPEC.SWIFT]

import SwiftUI

struct UserTypeC: View {
    let name:String
    let typeuser: TypeUser
    var body: some View {
        ZStack {
            // Definition background color
            Color.orange.edgesIgnoringSafeArea(.all)
            VStack{
                Text("Hello \(name)")
                Text("Your type is \(typeuser.description)")
            }
            .bold()
            .foregroundColor(.black)
            .font(.system(size: 30))
        }
    }
}

struct UserTypeC_Previews: PreviewProvider {
    static var previews: some View {
        UserTypeC(name: "TestName", typeuser: TypeUser.C)
    }
}


Finally, we modify the ContentView in order to show one of these View above, based on the value of TypeUser:
[CONTENTVIEW.SWIFT]

import SwiftUI

struct ContentView: View {
    let lstUser = Core().GetAllUsers()
    var body: some View {
        NavigationStack{
            List(lstUser) { user in
                NavigationLink(value: user){
                    Text("User: \(user.name)")
                }
            }
            .navigationTitle("Users list")
            // with navigationDEstination, we can choice the view to show
            .navigationDestination(for: User.self){ user in
                switch user.typeuser{
                case TypeUser.A:
                    UserTypeA(name: user.name, typeuser: user.typeuser)
                case TypeUser.B:
                    UserTypeB(name: user.name, typeuser: user.typeuser)
                case TypeUser.C:
                    UserTypeC(name: user.name, typeuser: user.typeuser)
                }
            }
        }
        
    }
}

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


We have done and now, if we run the application, these will be the results:



Leave a Reply

Your email address will not be published. Required fields are marked *