I have a NavigationManager to handle changing SwiftUI tab bar selection.
It work if it is set as a @EnvironmentObject
in my SwiftUI views, but not when the NavigationManager is called as a service in my view models. The thing is that I would like to use a simpler solution than passing around @EnvironmentObject var navigationManager
around and pass them inside view model initializer as I have a lot of them and I am looking for a cleaner approach.
How can I use my NavigationManager to change tabs from inside my view models without passing it in init()?
import SwiftUI
struct ContentView: View {
@StateObject var navigationManager = NavigationManager()
var body: some View {
TabView(selection: $navigationManager.selection) {
AccountView()
.tabItem {
Text("Account")
Image(systemName: "person.crop.circle") }
.tag(NavigationItem.account)
SettingsView()
.tabItem {
Text("Settings")
Image(systemName: "gear") }
.tag(NavigationItem.settings)
.environmentObject(navigationManager)
}
}
}
The navigation manager that I would like to use within view models.
class NavigationManager: ObservableObject {
@Published var selection: NavigationItem = .account
}
enum NavigationItem {
case account
case settings
}
My AccountViewModel and Settings View Model:
class AccountViewModel: ObservableObject {
let navigationManager = NavigationManager()
}
struct AccountView: View {
@StateObject var viewModel = AccountViewModel()
var body: some View {
VStack(spacing: 16) {
Text("AccountView")
.font(.title3)
Button(action: {
viewModel.navigationManager.selection = .settings
}) {
Text("Go to Settings tab")
.font(.headline)
}
.buttonStyle(.borderedProminent)
}
}
}
class SettingsViewModel: ObservableObject {
let navigationManager = NavigationManager()
}
struct SettingsView: View {
@EnvironmentObject var navigationManager: NavigationManager
@StateObject var viewModel = SettingsViewModel()
var body: some View {
VStack(spacing: 16) {
Text("SettingsView")
.font(.title3)
Button(action: {
navigationManager.selection = .account
}) {
Text("Go to Account tab")
.font(.headline)
}
.buttonStyle(.borderedProminent)
}
}
}