我有一个tabBar
。每个选项卡的ViewControllers
均已嵌入各自的NavigationControllers
中。
层次结构:
Tabbarcontroller
-> NavigationController
-> VC1-> VC2-> ... VCn(用于tab1)
当我单击推送通知时,我必须重定向到一个说VC2的视图控制器。我正在使用的代码如下。
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
}
使用此方法,我被重定向到相应的ViewController
。但是,我无法回到tabBar
。那么是否可以通过这样的方式进行重定向,使其允许我回到标签栏,从而提供与UI中相同的层次结构?
编辑:
下图显示了我的布局。
我想完成以下任务:
当用户点击推送通知时,应将应用程序定向到VC-B。 *如果VC-B已经在导航堆栈的顶部,则不应为VC-B创建新对象并将其添加到导航堆栈。
如果该应用已终止并且用户点击通知,则应打开VC-B。
为确定应用程序是否已终止,我将标志设置为:
func applicationWillTerminate(_ application: UIApplication) {
UserDefaults.standard.set(true, forKey: UserDefaultsKey.isTerminated)
}
在didFinishLaunchingWithOptions函数的末尾将此标志设置为false。
对于重定向,我检查此标志以确定应用是否已终止:
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)
}
}
}
}
使用此代码,部分满足了我的第一个要求。需要确定viewcontroller是否在导航堆栈的顶部。
并且,对于终止的应用程序,单击推送通知将打开选项卡栏,并选择默认的选择索引。
我花了几天的时间来解决这个问题。但是无法正常工作。
答案 0 :(得分:0)
好吧,您正在设置当前的window.rootViewController
,我应该说是TabBarViewController
。这就是为什么您无法回到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
}
答案 1 :(得分:0)
我想你必须做这样的事情:
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)
}
}
答案 2 :(得分:0)
从选项卡控制器获取当前的导航控制器。您可以使用此功能
override
使用该功能,您可以像下面那样浏览视图控制器。
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
}
答案 3 :(得分:0)
您可以在RootViewController中创建一个方法,该方法将在收到推送通知后将用户重定向到特定视图。这是我在上一个项目中所做的。
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
}
}
}
然后,您可以像这样在AppDelegate上调用该方法:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let application = UIApplication.shared
AppDelegate.shared.rootViewController.showDetailsScreen()
completionHandler()
}
}