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

Constructing routing in the app #66

Closed snowtema closed 3 years ago

snowtema commented 3 years ago

Hi,

What if I want to create a TabBar application and don't want to use Storyboards. How can I assemble configuration?

ekazaev commented 3 years ago

Hi @snowtema

you can build and integrate you Uitabbarcontroller the way you like. You can build it even manually and set it as a rootViewController of your view. Routcomposer just sits outside of your app structure and when you need to navigate somewhere it will update the graph of your view controllers according to the configuration you passed to the navigate method.

ekazaev commented 3 years ago

@snowtema One of the way can be:

let tabBarFactory = CompleteFactoryAssembly(factory: TabBarControllerFactory())
                                  .with(ClassFactory<HomeViewController, Any?>(), using: UITabBarController.add())
                                  .with(ClassFactory<AccountViewController, Any?>(), using: UITabBarController.add())
                                  .assemble()

// applicationDidFinishLaunching

let tabBarController = tabBarFactory.build()
window.rootViewController = tabBatController

window.makeKeyAndVisible()

// Later

let tabScreenConfiguration = SingleContainerStep(
            finder: ClassFinder(),
            factory: tabBarFactory)
            .using(GeneralAction.replaceRoot())
            .from(GeneralStep.root())
            .assemble()

router.commitNavigation(to: tabScreenConfiguration, with: nil, completion: nil)

You can reuse this factory in the routing configuration later. See advanced examples here

ekazaev commented 3 years ago

@snowtema please let me know what is confusing you

ekazaev commented 3 years ago

@snowtema Closing due to inactivity. Feel free to reopen if you'll have any questions.

snowtema commented 3 years ago

Hi, @ekazaev I tried code from your link (examples) and got this:

My tab bar configuration:

var tabBarScreen: DestinationStep<UITabBarController, Any?> {
        StepAssembly(
            finder: ClassFinder<UITabBarController, Any?>(options: .current, startingPoint: .root),
            factory: CompleteFactoryAssembly(factory: TabBarControllerFactory())
                .with(ClassFactory<TodayViewController, Any?>(), using: UITabBarController.add())
                .with(ClassFactory<ProfileViewController, Any?>(), using: UITabBarController.add())
                .assemble())
            .using(GeneralAction.replaceRoot())
            .from(GeneralStep.root())
            .assemble()
    }

On another screen (Splash) I call router.commitNavigation(to: ConfigurationHolder.configuration.tabBarScreen, animated: true, completion: nil) and tab bar items were set in view controller's viewDidLoad, and that's why I didn't see the Second tab while I don't click on it. The question is how I can configure the tab bar controller (tab names, etc) before display it? 2021-07-26 12 51 57

ekazaev commented 3 years ago

@snowtema That is the expected behaviour of viewDidLoad. The second view was not loaded, because it is not necessary until user actually switches to this tab. It is default and expected behaviour of the UITabBarController. You need to set up your title and tab bar items either in init method of the view controller or in the custom factory for your view controller. You can try to use the configuration: ((_: VC) -> Void)? = nil block of ClassFactory. But i would suggest you to create custom factories and setup everything there. You'll benefint from that in future.

snowtema commented 3 years ago

Okay, thanks. I'll try this. Also, I found in TabBarControllerFactory initializer configuration param. Can I use it for this?

ekazaev commented 3 years ago

You can, but then you are bringing knowledge of what is inside of tab bar to the tab bar factory, which kinda breaks encapsulation principle. But you can use it for the configuration of the UITabBarController itself.

snowtema commented 3 years ago

I'm trying to move from RxFlow to a better solution and found yours. At first sight, it looks more complex but more configurable :) Anyway, many thanks!

snowtema commented 3 years ago

Btw, factory solution works great )

ekazaev commented 3 years ago

@snowtema Happy to hear. Please don't hesitate to ask any questions you may have regarding the library

snowtema commented 3 years ago

Hi again! @ekazaev

I wanted to display a tab view controller with two tabs (Today and Account), and the account should lay down in the navigation controller?

How I can change my configuration to support Navigation in Account vc?

var tabBarScreen: DestinationStep<UITabBarController, Any?> {
        StepAssembly(
            finder: ClassFinder<UITabBarController, Any?>(options: .current, startingPoint: .root),
            factory: CompleteFactoryAssembly(factory: TabBarControllerFactory())
                .with(TodayFactory(), using: UITabBarController.add())
                .with(AccountFactory(), using: UITabBarController.add())
                .assemble())
            .using(GeneralAction.replaceRoot())
            .from(GeneralStep.root())
            .assemble()
    }
ekazaev commented 3 years ago

Hi @snowtema
if you are using composable factory aproach then just replace AccountFactory with another CompleteFactoryAssembly that will create a navigation controller with the Account factory inside

ekazaev commented 3 years ago

Example from one of the tests:

        let container = CompleteFactoryAssembly(factory: TabBarControllerFactory<UITabBarController, Any?>())
            .with(ClassFactory<UIViewController, Any?>())
            .adding(contextTask1)
            .adding(contextTask2)
            .with(ClassFactory<UIViewController, Any?>(), using: UITabBarController.add())
            .with(CompleteFactoryAssembly(factory: TabBarControllerFactory<UITabBarController, Any?>())
                .with(ClassFactory<UIViewController, Any?>()
                ).assemble(),
                using: UITabBarController.add(at: 1, replacing: true))
                .adding(contextTask3)
                .with(CompleteFactoryAssembly(factory: NavigationControllerFactory<UINavigationController, Any?>())
                    .with(CompleteFactoryAssembly(factory: TabBarControllerFactory<UITabBarController, Any?>())
                        .with(ClassFactory<UIViewController, Any?>()
                        ).assemble()
                    ).assemble())
                .assemble()
ekazaev commented 3 years ago

@snowtema I added a CompleteFactoryAssembly example for you. Please check InternalSearchConfiguration in the Example in the latest master.

snowtema commented 3 years ago

Thanks, will try this

snowtema commented 3 years ago

It works, many thanks.

ekazaev commented 3 years ago

@snowtema You are welcome.