[英]Properly redirect to a view controller inside tab bar's navigation controller when push notification is clicked
I have a tabBar
.我有一个tabBar
。 Each of its tabs' ViewControllers
have been embedded inside their respective NavigationControllers
.它的每个选项卡的ViewControllers
都嵌入在它们各自的NavigationControllers
。
Hierarchy:等级制度:
Tabbarcontroller
--> NavigationController
--> VC1 --> VC2 -->...VCn (for tab1) Tabbarcontroller
--> NavigationController
--> VC1 --> VC2 -->...VCn(用于 tab1)
I have to redirect to one of the viewcontrollers say VC2 when i click on push notifications.当我单击推送通知时,我必须重定向到其中一个视图控制器说 VC2。 The code i am using is as follows.我使用的代码如下。
let navigationController = UINavigationController()
let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
if let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as? ChatViewController {
navigationController.viewControllers = [chatViewController]
window?.rootViewController = navigationController
}
By using this, I am redirected to the respective ViewController
.通过使用它,我被重定向到相应的ViewController
。 However, i am not able to get back to the tabBar
.但是,我无法返回tabBar
。 So is it possible to redirect in such a way that it allows me the get back to the tab bar, thus providing the same hierarchy as in the UI?那么是否有可能以允许我返回标签栏的方式重定向,从而提供与 UI 中相同的层次结构?
EDIT:编辑:
The image below shows my layout.下图显示了我的布局。
I would like to accomplish the following:我想完成以下工作:
When the user taps the push notification, the app should be directed to VC-B.当用户点击推送通知时,应用程序应被定向到 VC-B。 *It should not create new object for VC-B and add to the navigation stack if VC-B is already on top of navigation stack. *如果 VC-B 已经在导航堆栈的顶部,它不应该为 VC-B 创建新对象并添加到导航堆栈。
If the app had been terminated and the user taps on the notification, it should open VC-B.如果应用程序已终止并且用户点击通知,则应打开 VC-B。
For determining if the app had been terminated, I set a flag as:为了确定应用程序是否已终止,我设置了一个标志:
func applicationWillTerminate(_ application: UIApplication) {
UserDefaults.standard.set(true, forKey: UserDefaultsKey.isTerminated)
}
This flag is set false at the end of didFinishLaunchingWithOptions function.该标志在 didFinishLaunchingWithOptions 函数结束时设置为 false。
For redirection, I check this flag to determine if the app had been terminated:对于重定向,我检查此标志以确定应用程序是否已终止:
func performRedirectionToSuitableViewController(userInfo: [AnyHashable: Any]) {
let isTerminated = UserDefaults.standard.object(forKey: UserDefaultsKey.isTerminated) as! Bool
if isTerminated {
let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let tab = storyboard.instantiateViewController(withIdentifier: "tabBar") as! UITabBarController
tab.selectedIndex = 0
let nav = tab.viewControllers![0] as! UINavigationController
let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as! ChatViewController
chatViewController.chatThreadId = userInfo["thread_id"] as? String
nav.pushViewController(chatViewController, animated: true)
} else {
if let tab = window?.rootViewController?.presentedViewController as? UITabBarController {
let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as! ChatViewController
chatViewController.chatThreadId = userInfo["thread_id"] as? String
if let nav = tab.selectedViewController as? UINavigationController {
nav.pushViewController(chatViewController, animated: true)
}
}
}
}
With this code, my first requirement is partially fulfilled.使用此代码,我的第一个要求部分满足。 Need to determine if the viewcontroller is at the top of the navigation stack.需要确定视图控制器是否位于导航堆栈的顶部。
And, in the case of terminated app, clicking the push notification opens the tab bar, with the default selection index being selected.并且,在应用终止的情况下,单击推送通知会打开标签栏,并选择默认选择索引。
I have spent several days trying to fix this.我花了几天时间试图解决这个问题。 But cannot get it work.但不能让它工作。
I suppose you have to do something like this:我想你必须做这样的事情:
let tabBar: UITabBarController // get your tab bar
tabBar.selectedIndex = 0 // eg. zero. To be sure that you are on correct tab
if let navigation = tabBar.viewControllers?[tabBar.selectedIndex] as? UINavigationController {
let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
if let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as? ChatViewController {
navigation.pushViewController(chatViewController, animated: true)
}
}
Well, you are setting current window.rootViewController
, which should be that TabBarViewController
I'd say.好吧,您正在设置当前window.rootViewController
,这应该是我要说的TabBarViewController
。 That's why you cannot get back to the TabBar
这就是为什么你不能回到TabBar
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
if let chatViewController = storyboard.instantiateViewController(withIdentifier: "chatViewController") as? ChatViewController, let tabBar = storyboard.instantiateViewController(withIdentifier: "tabBar") as? UITabBarController {
let navigationController = UINavigationController(rootViewController: chatViewController)
navigationController.viewControllers = [chatViewController]
tabBar.viewControllers = [navigationController]
window?.rootViewController = tabBar
}
To get the current navigation controller from the tabbar controller.从标签栏控制器获取当前导航控制器。 You can use this function你可以使用这个功能
func getVisibleViewController(_ rootViewController: UIViewController?) -> UIViewController? { var rootVC = rootViewController if rootVC == nil { rootVC = UIApplication.shared.keyWindow?.rootViewController } if rootVC?.presentedViewController == nil { return rootVC } if let presented = rootVC?.presentedViewController { if presented.isKind(of: UINavigationController.self) { let navigationController = presented as! UINavigationController return navigationController.viewControllers.last! } if presented.isKind(of: UITabBarController.self) { let tabBarController = presented as! UITabBarController return tabBarController.selectedViewController! } //UIAlertController if presented.isKind(of: UIAlertController.self) { let alertController = presented as! UIAlertController return alertController.presentingViewController } return getVisibleViewController(presented) } return nil }
Using the function you can navigate your viewcontroller like below.使用该功能,您可以像下面一样导航您的视图控制器。
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil) let yourView = mainStoryboardIpad.instantiateViewController(withIdentifier: "yourView") as! NewnoteViewController let navi = self.getVisibleViewController(self.window!.rootViewController) as! UINavigationController navi.pushViewController(yourView, animated: true)
You can create a method in your RootViewController that will redirect user to a specific view after receiving a push notification.您可以在 RootViewController 中创建一个方法,在收到推送通知后将用户重定向到特定视图。 Here's what I did in my previous project.这是我在之前的项目中所做的。
class RootViewController: UIViewController {
private var currentView: UIViewController
init() {
self.currentView = ViewController()
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
addChildViewController(currentView) // 1
currentView.view.frame = view.bounds // 2
view.addSubview(currentView.view) // 3
currentView.didMove(toParentViewController: self) // 4
}
func showDetailsScreen() {
if let updateDetailView = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "UpdateDetailsNotif") as? UpdateDetailsViewController{
let navController = UINavigationController(rootViewController: updateDetailView)
addChildViewController(navController)
navController.view.frame = view.bounds
view.addSubview(navController.view)
navController.didMove(toParentViewController: self)
currentView.willMove(toParentViewController: nil)
currentView.view.removeFromSuperview()
currentView.removeFromParentViewController()
currentView = navController
}
}
}
Then you can call that method on your AppDelegate like this:然后您可以像这样在 AppDelegate 上调用该方法:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let application = UIApplication.shared
AppDelegate.shared.rootViewController.showDetailsScreen()
completionHandler()
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.