Programmatic Navigation after opening notification SwiftUI [duplicate]
Solution 1:
You need some sort of shared state that you can modify that SwiftUI knows to react to. An ObservableObject
is perfect for this:
class AppState: ObservableObject {
static let shared = AppState()
@Published var pageToNavigationTo : String?
}
Then, to listen to it and respond to it, you can do a couple different methods in your main view.
Option 1 -- NavigationLink binding based on the value of the ObservedObject:
struct ContentView : View {
@ObservedObject var appState = AppState.shared //<-- note this
@State var navigate = false
var pushNavigationBinding : Binding<Bool> {
.init { () -> Bool in
appState.pageToNavigationTo != nil
} set: { (newValue) in
if !newValue { appState.pageToNavigationTo = nil }
}
}
var body: some View {
NavigationView {
Text("My content")
.overlay(NavigationLink(destination: Dest(message: appState.pageToNavigationTo ?? ""),
isActive: pushNavigationBinding) {
EmptyView()
})
}
}
}
struct Dest : View {
var message : String
var body: some View {
Text("\(message)")
}
}
Or, you could use onReceive
:
struct ContentView : View {
@ObservedObject var appState = AppState.shared
@State var navigate = false
var body: some View {
NavigationView {
VStack {
if navigate {
NavigationLink(destination: Text("Test"), isActive: $navigate ) {
EmptyView()
}
}
Text("My content")
.onReceive(appState.$pageToNavigationTo) { (nav) in
if nav != nil { navigate = true }
}
}
}
}
}
I'll leave the implementation details of your specific NavigationView, NavigationLink, TabView, etc to you, but this should get you started.
Finally, a fully-functional minimal example that mocks a notification and shows how the navigation view:
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
print("Dispatch")
AppState.shared.pageToNavigationTo = "test"
}
return true
}
}
class AppState: ObservableObject {
static let shared = AppState()
@Published var pageToNavigationTo : String?
}
@main
struct MultiWindowApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView : View {
@ObservedObject var appState = AppState.shared
@State var navigate = false
var pushNavigationBinding : Binding<Bool> {
.init { () -> Bool in
appState.pageToNavigationTo != nil
} set: { (newValue) in
if !newValue { appState.pageToNavigationTo = nil }
}
}
var body: some View {
NavigationView {
Text("My content")
.overlay(NavigationLink(destination: Dest(message: appState.pageToNavigationTo ?? ""),
isActive: pushNavigationBinding) {
EmptyView()
})
}
}
}
struct Dest : View {
var message : String
var body: some View {
Text("\(message)")
}
}