7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SwiftUIだけど画面遷移はUIKitでやる

Posted at

画面遷移処理を各画面から切り離したり、カスタムURLスキームなどを使って任意の画面に遷移できるようにする処理をSwiftUIでもやりたい。でもSwiftUIだけで実現する方法がわからない。。。
難しそうなところは今後のSwiftUIの進化に期待するということで、画面遷移は無理せずUIKitベースでやってしまえば良さそうだなと思い始めました。

環境

  • Xcode 12.0

実装

各画面のレイアウトはSwiftUIでさくっと作ってしまって画面遷移に関連する部分はUIKitベースで処理するために、遷移先はUIHostingControllerを使う。ViewControllerを見つける処理は従来通り。

var window: UIWindow? {
    guard let window = (UIApplication.shared.connectedScenes.first?.delegate as? UIWindowSceneDelegate)?.window else { return nil }
    return window
}

/// 全面に表示されているViewControllerを見つける
func topViewController(_ vc: UIViewController? = nil) -> UIViewController? {
    guard let vc = vc ?? window?.rootViewController else { return nil }
    if let presented = vc.presentedViewController {
        return topViewController(presented)
    }
    return vc
}

/// NavigationControllerを見つける
func navigationController(_ vc: UIViewController) -> UINavigationController? {
    if let result = vc as? UINavigationController {
        return result
    }
    for child in vc.children {
        if let result = navigationController(child) {
            return result
        }
    }
    return nil
}

@main
struct MainApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL(perform: { _ in
                    guard let topVC = topViewController() else { return }
                    if let navVC = navigationController(topVC) {
                        navVC.show(UIHostingController(rootView: TestView()), sender: nil)
                    } else {
                        topVC.present(UIHostingController(rootView: NavigationView(content: { TestView() })),
                                      animated: true,
                                      completion: nil)
                    }
                })
        }
    }
}

SwiftUIで作った画面をXcodeのDebug View Hierarchyで見てみると、ViewControllerらしきコンポーネントがたくさん使われているようだったので、上記の実装は「NavigationViewを使えばUINavigationControllerが内部的には使われているかもしれない」とか、「sheetでモーダル表示したらpresentedViewControllerで遷移先のViewControllerを見つけられるかもしれない」という思い込みで実装してみました。
SwiftUIのNavigationViewを使っている場合にUINavigationControllerを探索可能かどうか不明でしたが、UINavigationControllerを継承していそうなクラスが使われているようでした。

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?