使用Swift从应用程序委托打开视图控制器

81

我正在尝试创建一个推送通知,根据从推送中获取的信息确定要打开哪个视图。

我已经成功地从推送中获取了信息,但现在我无法打开视图。

查看其他堆栈溢出问题,我目前有以下内容:

应用程序委托 didFinishLaunchingWithOptions:

     //Extract the notification data
    if let notificationPayload = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
        // Get which page to open
        let viewload = notificationPayload["view"] as? NSString
        let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
        //Load correct view
        if viewload == "circles" {

            var viewController = self.window?.rootViewController?.storyboard?.instantiateViewControllerWithIdentifier("Circles") as! UIViewController
            self.window?.rootViewController = viewController

                        }
    }

目前在 var ViewController = self... 这一行出现了错误。


请查看这个答案。 - Borzh
2
我尝试了这个方法,它可以打开“Circles”视图控制器。但是假设“Circles”视图控制器本身位于我的应用程序导航树的子树中,那么我该如何确保一旦在“Circles”视图控制器中打开我的应用程序,所有后退导航都能正常工作?目前,它会打开“Circles”视图控制器,但不显示后退导航。 - Dogahe
11个回答

119

您需要按照下面图像设置ViewController的StoryBoardId属性。

enter image description here

在Swift中,可以使用以下编程方式打开viewController。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

         let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
         let initialViewControlleripad : UIViewController = mainStoryboardIpad.instantiateViewControllerWithIdentifier("Circles") as UIViewController
         self.window = UIWindow(frame: UIScreen.main.bounds)
         self.window?.rootViewController = initialViewControlleripad
         self.window?.makeKeyAndVisible()

         return true
    }

iOS 13+(基于 dev2qa的文章
打开 SceneDelegate.swift 文件并添加以下内容

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

    // If this scene's self.window is nil then set a new UIWindow object to it.
    self.window = self.window ?? UIWindow()

    // Set this scene's window's background color.
    self.window!.backgroundColor = UIColor.red

    // Create a ViewController object and set it as the scene's window's root view controller.
    self.window!.rootViewController = ViewController()

    // Make this scene's window be visible.
    self.window!.makeKeyAndVisible()

    guard scene is UIWindowScene else { return }
}

有一个开源的导航工具,旨在使这变得更加容易。示例


2
但这将创建控制器的新实例。我想要已经具有状态的控制器。或者我错过了什么? - rjcarr
应用程序委托方法在接收用户通知时没有被调用,为什么? - ArgaPK
同样适用于 Swift 版本,但只需更改语法即可。 - Kirit Modi
但是在那个视图控制器(“circles”)中,viewDidLoad没有起作用。 - Rashid KC
1
最新消息:将答案代码放入 SceneDelegate.scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) 中(FYI,我基于 创建了一个 导航工具)。 - MD TAREQ HASSAN

56

Swift 3:

当从AppDelegate通过当前视图控制器呈现新的视图控制器时,这是我首选的方法。这样,在处理推送通知或通用链接时,您不必完全摧毁您的视图层次结构。

if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "someController") as? SomeController {
    if let window = self.window, let rootViewController = window.rootViewController {
        var currentController = rootViewController
        while let presentedController = currentController.presentedViewController {
            currentController = presentedController
        }
        currentController.present(controller, animated: true, completion: nil)
    }
}

2
这是最佳方法,你也可以关闭此视图self.dismiss(animated: true, completion: nil) - Imtee
@Imtee:你是指关闭当前显示的视图控制器吗? - Lohith Korupolu
@LohithKorupolu,如果您想要从当前的视图控制器中移动。 - Imtee
我之前使用了被接受的答案,但在管理视图层次结构方面遇到了问题,而这正是我们所需要的! - Z. Bagley
1
@KrutikaSonawala,使用self.dismiss(animated: true, completion: nil)希望能够起作用。 - Imtee
显示剩余5条评论

14

Swift 3

将视图与导航控制器一起呈现:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier :"InboxViewController") as! InboxViewController
let navController = UINavigationController.init(rootViewController: viewController)

   if let window = self.window, let rootViewController = window.rootViewController {
       var currentController = rootViewController
       while let presentedController = currentController.presentedViewController {
           currentController = presentedController
        }
           currentController.present(navController, animated: true, completion: nil)
   }

这个可以工作...但是如果你有一个 tabBar,那么 tabBar 就不会显示。 - xhinoda

8

首先,初始化 window

self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyBoard = UIStoryboard(name: "Main", bundle: nil)

AppDelegate 类中设置 rootViewController
let viewController = storyBoard.instantiateViewControllerWithIdentifier("Circles") as UIViewController
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()

6

有一个Swift 4版本

func application(_ application: UIApplication, 
didFinishLaunchingWithOptions launchOptions: 
[UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewControlleripad : UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "Circles") as UIViewController
            self.window = UIWindow(frame: UIScreen.main.bounds)
            self.window?.rootViewController = initialViewControlleripad
            self.window?.makeKeyAndVisible()

return true}

5

在 Swift 3 中

        let mainStoryboard : UIStoryboard = UIStoryboard(name: StorybordName, bundle: nil)
        let initialViewControlleripad : UIViewController = mainStoryboard.instantiateViewController(withIdentifier: identifierName) as UIViewController
        if let navigationController = self.window?.rootViewController as? UINavigationController
        {
            navigationController.pushViewController(initialViewControlleripad, animated: animation)
        }
        else
        {
            print("Navigation Controller not Found")
        }

3
我认为每次想要更改rootViewController时创建UIWindow是个不好的主意。使用上述方法多次更改rootVC后,你的应用程序会同时有很多UIWindows。
在我看来,更好的解决方案是:
  1. 获取新的rootVC:let rootVC = UIStoryboard(name: "StoryboardName", bundle: nil).instantiateViewControllerWithIdentifier("newRootVCIdentifier") as UIViewController
  2. 将新的rootVC设置为UIScreen的边界框: rootVC.view.frame = UIScreen.mainScreen().bounds
  3. 为当前窗口设置新的根控制器(这里带有动画):UIView.transitionWithView(self.window!, duration: 0.5, options: .TransitionCrossDissolve, animations: { self.window!.rootViewController = rootVC }, completion: nil)
完成!
你不需要使用window?.makeKeyAndVisible()方法,因为此解决方案适用于当前应用程序窗口。

如何关闭此 VC? - Krutika Sonawala

3

Swift 3 SWRevealViewController

    self.window = UIWindow(frame: UIScreen.main.bounds)
    let storyBoard = UIStoryboard(name: "Main", bundle: nil)

    let viewController = storyBoard.instantiateViewController(withIdentifier: "SWRevealViewController") as! SWRevealViewController
    self.window?.rootViewController = viewController
    self.window?.makeKeyAndVisible()

如果我使用此代码从扩展中打开应用程序,navigationcontroller会变为nil。你有什么解决办法吗? - ashif-ismail

1
let storyboard = UIStoryboard(name: "Main", bundle: nil)

    let destinationViewController = storyboard.instantiateViewController(withIdentifier: "LandVC") as! LandingPageVC

    destinationViewController.webpageURL = NotificationAdvertisement._htmlpackagePath
    destinationViewController.adID = NotificationAdvertisement._adID
    destinationViewController.toneID = NotificationAdvertisement.toneID

    let navigationController = self.window?.rootViewController as! UIViewController

    navigationController.showDetailViewController(destinationViewController, sender: Any?.self)

0

SWIFT 4

let storyboard = UIStoryboard(name: "Main", bundle: nil)

    let destinationViewController = storyboard.instantiateViewController(withIdentifier: "LandVC") as! LandingPageVC

    destinationViewController.webpageURL = NotificationAdvertisement._htmlpackagePath
    destinationViewController.adID = NotificationAdvertisement._adID
    destinationViewController.toneID = NotificationAdvertisement.toneID

    let navigationController = self.window?.rootViewController as! UIViewController

    navigationController.showDetailViewController(destinationViewController, sender: Any?.self)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接