🦋

SwiftUIのViewからUIKitのnavigationControllerにアクセスする方法

2022/07/04に公開

UIKitベースのアプリでも、UIHostingController(rootView:)を使ってSwiftUIのViewを埋め込むことができますが、SwiftUIのViewの中でUIKitのnavigationControllerにアクセスしたいことがあるかもしれません。そういう時はUIApplication.sharedからSceneWindowViewControllerを手繰り寄せて再帰的に最前面のViewControllerを探し出す事で、そのnavigationControllerを取得することが可能です。

var navigationController: UINavigationController? {
    guard let scene = UIApplication.shared.connectedScenes.first,
          let sceneDelegate = scene as? UIWindowScene,
          var controller = sceneDelegate.windows.first?.rootViewController
    else { return nil }
    while true {
        if let navigationController = controller as? UINavigationController,
           let visibleViewController = navigationController.visibleViewController {
            controller = visibleViewController
            continue
        }
        if let tabBarController = controller as? UITabBarController,
           let selectedViewController = tabBarController.selectedViewController {
            controller = selectedViewController
            continue
        }
        if let presentedViewController = controller.presentedViewController {
            controller = presentedViewController
            continue
        }
        break
    }
    return controller.navigationController
}

これでnavigationControllerがどこでも手に入るので(もちろんない時はない)、さらにUIHostingController(rootView:)を使ってUINavigationControllerの世界で画面遷移することも可能です。

Button {
    let hostingController = UIHostingController(rootView: HogeView())
    hostingController.title = "Hoge"
    navigationController?.pushViewController(hostingController, animated: true)
} label: {
    Text("画面遷移")
}

Discussion