我正在开发 SwiftUI 应用程序,我面临一个有关通知的问题。当用户点击通知时,我试图导航到特定屏幕。现在我正在做的是,每当我收到通知并且用户点击通知时,我的 viewModifier .onNotification 就会被调用,并且在其中我使用 ChatNotificationHandler 类保存通知数据,以便稍后当我打开 chattingView 来显示详细信息时可以利用这些数据正在获取新数据。
我还可以从其中监听通知点击查看仪表板,以便我可以使用 .navigationDestination 修饰符导航到聊天视图。
我有这个视图层次结构
仪表板屏幕 -> 收件箱视图 -> 聊天视图
当我在 DashboardScreen 上时,如果我收到通知并点击它,那么它应该打开工作正常的 ChattingView,然后如果我单击后退按钮,它应该再次弹出到 DashboardScreen,这也工作正常。但是当我在 InboxView 上并在收到通知时移动到 ChattingView 时,出现了问题,然后如果我单击后退按钮,它会弹出到 DashboardScreen 而不是 InboxView。所以我不知道为什么它会这样。但我认为它的行为是这样的,因为我正在从 DashboardScreen 监听和推送,这就是为什么它会弹出到 DashboardScreen 而不是 InboxView。那么您能否帮我解决这个问题,并告诉我应该从哪里推送到 ChattingView,以便它始终弹出到正确的视图。
这是我的内容视图
struct ContentView: View {
@EnvironmentObject var appState: AppState
@StateObject var deepLinkViewModel: DeepLinkViewModel = DeepLinkViewModel()
var body: some View {
Group {
if appState.isLoggedIn || OnBoardingAuthentication.isUserLoggedIn() {
DashboardScreen()
.onNotification { notificationResponse in
let userInfo = notificationResponse.notification.request.content.userInfo
let (type, data) = NotificationHandler.shared.getNotificationTypeAndData(response: userInfo)
if type == NotificationType.chat {
guard let chatData = data else { return }
ChatNotificationHandler.shared.saveChatDataAfternotification(jsonBody: chatData)
appState.moveToChattingView = true
ChatConfigurationManager.shared.configure()
}else if type == NotificationType.call { }
}
} else {
LoginView(viewModel: LoginViewModel(nil))
}
这是我的 DashboardScreen 监听器和修改器
.navigationDestination(isPresented: self.$isNavigateToChattingView, destination: {
if self.isNavigateToChattingView {
ChattingView(selectedRemoteUser: chatAppState.notificationChatData, organizationId: chatAppState.notificationOrganisationId ?? "", isFromTransferring: false)
}
})
.onReceive(self.appState.$moveToChattingView) { moveToChatView in
if moveToChatView {
ChatConfigurationManager.shared.configure()
self.isNavigateToChattingView = true
}
}
最后我像这样从 ChattingView 中弹出
NavigationBarView(receiverDetail: viewModel.receiverDetail, userStatus: viewModel.receiverStatus, isUserTyping : viewModel.isRemoteUserTyping, onTapBackCallback:
{
viewModel.messagesDataArr.removeAll()
self.dismiss()
})
在 SwiftUI 中基于通知浏览视图可能很棘手,尤其是在处理嵌套导航并希望导航层次结构中的后退按钮具有特定行为时。在您的情况下,可以通过更明确地管理导航堆栈来解决从 ChattingView 错误导航回 DashboardScreen 而不是 InboxView 的问题。预先警告一下,我可以提供一个示例来说明您应该如何进行此操作,但这将需要大量返工。
从您的描述和代码片段来看,无论用户当前在应用程序中的位置如何,到 ChattingView 的导航似乎总是从 DashboardScreen 启动。每当点击通知时,这都会将导航堆栈重置为从 DashboardScreen 开始,这就是您看到弹回 DashboardScreen 的行为的原因。
要解决此问题并确保从 ChattingView 弹出返回到正确的先前视图(InboxView 或 DashboardScreen),您需要修改处理导航状态的方式以及可能构建导航逻辑的方式。
第 1 步:更新导航处理
不要使用单个布尔标志 (isNavigateToChattingView) 来控制到 ChattingView 的导航,而是考虑使用更灵活的导航路径方法。此处可以利用 SwiftUI 的 NavigationPath 以更受控的方式推送和弹出视图。
@State private var navPath = NavigationPath()
var body: some View {
NavigationStack(path: $navPath) {
Group {
if appState.isLoggedIn || OnBoardingAuthentication.isUserLoggedIn() {
DashboardScreen()
.onNotification { notificationResponse in
handleNotification(notificationResponse)
}
} else {
LoginView(viewModel: LoginViewModel(nil))
}
}
}
}
func handleNotification(_ notificationResponse: UNNotificationResponse) {
let userInfo = notificationResponse.notification.request.content.userInfo
let (type, data) = NotificationHandler.shared.getNotificationTypeAndData(response: userInfo)
switch type {
case .chat:
if let chatData = data {
ChatNotificationHandler.shared.saveChatDataAfternotification(jsonBody: chatData)
navigateToChatView()
ChatConfigurationManager.shared.configure()
}
case .call:
// Handle call notification if needed
break
default:
break
}
}
func navigateToChatView() {
navPath.append(ChatViewID) // Define ChatViewID as a constant or enum that identifies ChattingView
}
确保两个视图使用相同的 NavigationStack 和 navPath 以保持导航历史记录的一致性。
第 2 步:自定义后退按钮处理
在ChattingView中,您需要显式管理后退导航以确保它弹出到正确的视图。您可以修改后退按钮操作以直接操作导航路径。
ChattingView 示例:
NavigationBarView(receiverDetail: viewModel.receiverDetail, userStatus: viewModel.receiverStatus, isUserTyping: viewModel.isRemoteUserTyping, onTapBackCallback: {
viewModel.messagesDataArr.removeAll()
if navPath.count > 1 {
navPath.removeLast()
} else {
// Default action if needed
self.dismiss()
}
})
此解决方案需要了解我所不具备的导航流程,因此您需要根据此处未显示的应用程序的其他部分进行调整。关键是保持一致且清晰的导航堆栈,您可以根据用户操作和通知处理进行修改。