eugene_prg
eugene_prg

Reputation: 1168

Building navigation between Views in my iOS app

As the time flies, by App get more and more complicated shape.

In some cases the App flow might be:

View A -> View B -> C -> D and then back D -> C -> B -> A..

but sometimes i need to skip the view and go D -> B -> A..

In some cases its A -> C -> D and then D -> A

I started to use NavigationView/NavigationLink and in some cases i use the following approach:

let weekView = WeekView(journey: journey, isRoot: isRoot).environmentObject(self.thisSession)
        window?.rootViewController = UIHostingController(rootView: weekView)

No i realize that it has become a complete mess.. It's time for me to rethink this..

How do you handle navigation in apps where it can't be always done by pushing/popping the views from Navigation stack?

Upvotes: 1

Views: 104

Answers (1)

Sergio Bost
Sergio Bost

Reputation: 3239

Using ViewBuilders is a good option here.

  @ViewBuilder func myViewRouter(selection: Selection) -> some View {
         switch selection { 
            case selection1:
                View1()
            case selection2:
                View2()
            case selection3: 
                View3()
    
          }
    }

 enum Selection { ... }

ViewBuilders are powerful, its pretty much a function that can return opaque types but notice the lack of the return keyword. This seems like a perfect use case for it. In the example I used a enum but its also common to see this used with a var selection = 0 on the parent view and have the ViewBuilder as the child. Either way, same functionality.

Below is is a good url to understand ViewBuilders.

https://swiftwithmajid.com/2019/12/18/the-power-of-viewbuilder-in-swiftui/

Last edit: Here is an example use case:

import SwiftUI

struct ContentView: View {
    @State private var selection: SelectionEnum = .zero
    var body: some View {
        VStack {
            showMyViews(selection: selection)
            HStack {
                ForEach(SelectionEnum.allCases, id: \.self) { selection in
                    Button(action: {self.selection = selection}){
                        Text(selection.rawValue)
                            .fontWeight(.bold)
                            .frame(width: 60, height: 60)
                            .foregroundColor(.white)
                            .background(Color.blue)
                            .cornerRadius(10)
                    }

                }
            }
            
            }

        
    }
    
    @ViewBuilder func showMyViews(selection: SelectionEnum) -> some View {
        switch selection {
        case .zero:
            ViewA()
        case .one:
            ViewB()
        case .two:
            ViewC()
        case .three:
            ViewD()
        }
    }
    enum SelectionEnum: String, CaseIterable {
        case zero
        case one
        case two
        case three
    }
}

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

struct ViewA: View {
    var body: some View {
        Text("View A")
    }
}

struct ViewB: View {
    var body: some View {
        Text("View B")
    }
}

struct ViewC: View {
    var body: some View {
        Text("View C")
    }
}

struct ViewD: View {
    var body: some View {
        Text("View D")
    }
}

Upvotes: 1

Related Questions