John Marc

Follow @ioloro on Micro.blog.

Simple EnviormentObject and Published method to show different views

So, you’ve got a single view container, let’s call it “ControlCenter” that you want to show one of three sets of controls within. Typically you’d write three views, and try to intiatiate these views, push/pulling into focus.

With SwiftUI creating a centralized method where the views are unaware of when/why they will appear, but also the ability to summon these views should be possible by any other arbitrary portion of the app.

Enter @EnviormentObject and @Published

First lets create our data/control class:


   //  CommandCenterManager.swift
   //  Created by John Marc on 1/9/23.

   class CommandCenterManager: ObservableObject {
      @Published var currentView: CurrentView
      
      init() {
         currentView = .first
      }
      
      enum CurrentView {
         case first, second, third
      }
      
      func getViewPosition(currView: CurrentView) -> Int {
         var viewPosition = 0
         
         if currView == .first {
            viewPosition = 1
         }
         
         if currView == .second {
            viewPosition = 2
         }
         
         if currView == .third {
            viewPosition = 3
         }
         
         return viewPosition
      }
      
      func getNextView() {
         let currentPos = getViewPosition(currView: self.currentView)
         
         print("CurrentView: \(self.currentView)")
         if currentPos == 1 {
            currentView = .second
         }
         if currentPos == 2 {
            currentView = .third
         }
         if currentPos == 3 {
            currentView = .first
         }
         
         print("NextView: \(self.currentView)")
      }
   }

From there, on app creation let’s tell our app about this EnviormentObject:

   //  CommandCenterApp.swift
   //  Created by John Marc on 1/9/23.

   import SwiftUI

   @main
   struct CommandCenterApp: App {
      @StateObject var ccm = CommandCenterManager()
      
       var body: some Scene {
           WindowGroup {
               ContentView()
               .environmentObject(ccm)
           }
       }
   }

Excellent, let’s create the container to hold our views and the views themselves:

   //  CommandCenterViews.swift
   //  Created by John Marc on 1/9/23.

   import Foundation
   import SwiftUI

   struct CurrentView: View {
      @EnvironmentObject var ccm: CommandCenterManager
      
      var body: some View {
         switch ccm.currentView {
         case .first:
            FirstView()
         case .second:
            SecondView()
         case .third:
            ThirdView()
         }
      }
   }


   struct FirstView: View {
      var body: some View {
         VStack {
            Text("FirstView")
         }
         .frame(width: 500, height: 500)
         .background(.red)
      }
   }


   struct SecondView: View {
      var body: some View {
         VStack {
            Text("SecondView")
         }
         .frame(width: 500, height: 500)
         .background(.green)
      }
   }

   struct ThirdView: View {
      var body: some View {
         VStack {
            Text("ThirdView")
         }
         .frame(width: 500, height: 500)
         .background(.blue)
      }
   }

And finally the view that calls into this CurrentView:

   //  ContentView.swift
   //  Created by John Marc on 1/9/23.

   import SwiftUI

   struct ContentView: View {
      @EnvironmentObject var ccm: CommandCenterManager
      
       var body: some View {
         VStack {
            CurrentView()
            Button("Next View", action: {
               ccm.getNextView()
            })
         }
       }
   }

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