Supporting SwiftUI navigation in legacy projects
Asked Answered
T

1

12

I'm wondering if there's any way to start using SwiftUI in a legacy project and still be able to navigate back and forth SwiftUI scenes. That is, let's imagine I just want to support the last iOS 13 for a project I've been working on for the last year. Everything is built upon UIKit and navigations happen the usual way presenting or pushing viewcontrollers.

Now I want to start using SwiftUI so I enable the option in the General of my project, target iOS 13, get my SceneDelegate and my new key-value pair in Info.plist. In order to navigate to a Swift UI scene, I can just push a UIHostingViewController whose rootView will be my newly designed SwiftUI View. But how can I use NavigationLink to push an old UIKit view controller?

class ViewController: UIViewController {

    @IBAction func userDidTapGo(_ sender: Any) {
        let contentView = ContentView()
        navigationController?.pushViewController(UIHostingController(rootView: contentView), animated: true)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        title = "UIKit"
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: /* what should be here?? */) {
                Text("Go to UIKit")
            }

        }.navigationBarTitle("Swift UI")
    }
}
Tali answered 17/9, 2019 at 12:38 Comment(8)
My advice? If your project is a Storyboard project, do not make your root VC be a UIHostingViewController or the root view be a SwoftUI View. Period. Since you have a storyboard and a UINavigationController already working, just navigate (or push) the hosting VC onto the stack and use Compose or Notifications to navigate from there. In other words, get rid of the NavigationView in your ContentView, change your NavigationLink to be a SwiftUI Button, and set it's action to tell your UIKit navigation to push/pop the stack.Cachepot
Is there a way to get the navigation controller in a SwiftUI View to push or pop the stack? Or would I have to pass it as an initializer argument?Tali
First, I didn't downvote your question - I think I understand what you're asking. And if so, it's something that's (probably?) not possible. (Yet?) But think through something deeper - the complexity of everything you want. Why not start with a SwiftUI app if you are taking your legacy app into some kind of fork that only supports iOS 13? Why not port your UIKit views and VCs into representable views? Finally, if you must keep your iOS 13 app as something that is more UIKit than SwiftUI, why not let navigation something that is deeply tied to everything, be part of that? Cont.Cachepot
#2: In the end, SwiftUI is not a "layer" on top of UIKit (nor is the reverse true). It's truly a separate stack - in Xcode, it's part of the second screen when you define your new project. I've given you what I think is a working option. And if you really are forking a UIKit app targeting iOS 12 and under, it should work - just move the navigation from SwiftUI to UIKit, and communicate between your different stacks through Combine or notifications. One last comment....Cachepot
#3: I"m actually doing the opposite - my SwiftUI app (not legacy) embeds a UINavigationController with two table views because I'm not happy with how raw things like layout and customizing a navigation controller work. While I asked a question about communicating a UIButton click to SwiftUI (and had a really good suggestion) I ended up going back to something I could get working - Notifications. It's a single view SwiftUI app, but where I needed navigation, it's a "child subview" that's a UIViewControllerRepresentable that subclasses UINavigationController. I sincerely wish you luck!Cachepot
Thanks for you comments, @dfd. Really. I don't understand why people downvoted my question, perhaps it's my English. Surely I wouldn't target iOS 13 and remove support for older versions just to import SwiftUI. I was just wondering, what will happen in 2-3 years when the last version supported is iOS 13. Will it be possible to include this framework in legacy projects that originally worked with UIKit? I agree that right now it is not possible or at least, too complicated and nonsense.Tali
I think this should answer your question: #57966340Defer
To your last question I'd say look to the past. Cocoa/Carbon, AppKit/UIKit, and in 2 days, AppKit/UIKit/WatchKit/SwiftUI. There's no doubt - none - that someday it will all be SwiftUI. But when Carbon lasted 8 years (killed with 64 bit) and AppKit is still around, and, as Apple proudly points out a few times a year, UIKit is a billion $$ industry with millions of apps... well, I don't know how old you are but you may be retired before UIKit goes away! (And I'm only talking software, not OS, not hardware.)Cachepot
C
1

You'll need to wrap you old view controllers in a UIViewControllerRepresentable wrapper. There is a nice tutorial by Apple: Interfacing with UIKit.

It works great, lets you reuse old code instead of rewriting everything from scratch.

Cockleshell answered 18/9, 2019 at 13:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.