ekazaev / route-composer

Protocol oriented, Cocoa UI abstractions based library that helps to handle view controllers composition, navigation and deep linking tasks in the iOS application. Can be used as the universal replacement for the Coordinator pattern.
MIT License
896 stars 63 forks source link

Is it compatible with swiftUI? #53

Closed vBoykoGit closed 4 years ago

vBoykoGit commented 4 years ago

Could you provide some examples of routing and building view with swiftUI?

ekazaev commented 4 years ago

@vBoykoGit It is compatible, as SwiftUI still sits within UIViewControllers. And RootComposer operates with them. Just default Finders and Factoriyies need to be tweaked though. I did couple experiments. But as imho SwiftUI is still in a Proof of concept state I haven't gone any further yet, so I do not have anything production ready. Sorry about that. But, with this lockdown Ill probably will have a better look.

ekazaev commented 4 years ago

I will try to add something here. I had it stashed somewhere. Basically they need to support UIHostingController

ekazaev commented 4 years ago

@vBoykoGit I found something for you

Factory/Finder will look like this: I wrote with context to be equatable. But I am sure you can adapt it to be used with any type of context by the example with the finders that are present already

#if os(iOS)

import Foundation
import UIKit

import SwiftUI

public protocol ContextInstantiatable {

    associatedtype Context

    var context: Context { get }

    init(context: Context)

}

@available(iOS 13.0.0, *)
public struct UIHostingControllerFactory<ContentView: View & ContextInstantiatable>: Factory {

    public typealias ViewController = UIHostingController<ContentView>

    public typealias Context = ContentView.Context

    public init() {
    }

    public func build(with context: Context) throws -> UIHostingController<ContentView> {
        let viewController = UIHostingController(rootView: ContentView(context: context))
        return viewController
    }

}

@available(iOS 13.0.0, *)
public struct UIHostingControllerFinder<ContentView: View & ContextInstantiatable>: StackIteratingFinder where ContentView.Context: Equatable {

    public typealias ViewController = UIHostingController<ContentView>

    public typealias Context = ContentView.Context

    public let iterator: StackIterator

    public init(iterator: StackIterator = DefaultStackIterator()) {
        self.iterator = iterator
    }

    public func isTarget(_ viewController: ViewController, with context: Context) -> Bool {
        return viewController.rootView.context == context
    }

}

#endif

Lets assume that your SwiftUIView looks like this:

import Foundation
import SwiftUI
import RouteComposer

@available(iOS 13.0.0, *)
struct ContentView: View, ContextInstantiatable {

    let context: String

    init(context: String) {
        self.context = context
    }

    var body: some View {
        Text("Hello SwiftUI. Context is \(context)")
    }

}

So configuration to present it within tab bar will look like this:

let step = StepAssembly(
            finder: UIHostingControllerFinder<ContentView>(),
            factory: UIHostingControllerFactory()
        )
        .using(UITabBarController.add())
        .from(homeScreen.adaptingContext())
        .assemble()

try? router.navigate(to: step, with: "Test Context")

Which will bring you here:

Screenshot 2020-03-24 at 20 45 04
ekazaev commented 4 years ago

You can check out the example project here: https://github.com/ekazaev/route-composer/tree/chore/swift-ui-support

Please keep in mind that I just applied the stash I had. But similar factories/finders will be available in the library later. So you will be able to replace your implementations with the library ones.

ekazaev commented 4 years ago

@vBoykoGit Please let me know if you'll need any further help

ekazaev commented 4 years ago

@vBoykoGit Closed due to inactivity.