Home > Software design >  TabBarController with Coordinators (MVVM-C) - Opening the same ViewController in different tabs
TabBarController with Coordinators (MVVM-C) - Opening the same ViewController in different tabs

Time:10-05

I have a TabBarCoordinator with 2 tabs: One for a list of movies (MoviesListViewController) with FirstTabCoordinator, and one for favorite movies (FavoritesViewController) with SecondTabCoordinator, both with a tableView, and each tab has its own navigationController. When I tap on a movie, in the movie list tab or favorites tab, I push the MovieDetailsViewController. This works fine. But in the MovieDetailsViewController I have another collection of Similar Movies.
My problem is:
In MovieDetailsViewController, when I tap on a similar movie, on didSelectItemAt indexPath, how do I tell in which coordinator to push the next MovieDetailsViewController? Because I can get to movie details from both coordinators.

I think I may have to add some sort of mechanism between those 2 coordinators, but I'm not sure..

This is my MainCoordinator

protocol Coordinator {
  func startCoordinator()
}
    
class MainCoordinator: Coordinator {
  var tabBarController = UITabBarController()
  
  static func getCoordinator() -> MainCoordinator? {
    if let scene = UIApplication.shared.connectedScenes.first, let delegate = scene.delegate as? SceneDelegate {
      return delegate.coordinator
    }
    return nil
  }
  
  func startCoordinator() {
    FirstTabCoordinator.shared.startCoordinator()
    let moviesListVC = FirstTabCoordinator.shared.moviesListViewController
    self.setupTabBarItem(vc: moviesListVC,
                     title: "All Movies",
                     imageName: "film",
                     selectedImageName: "film.fill")
    
    SecondTabCoordinator.shared.startCoordinator()
    let favoritesVC = SecondTabCoordinator.shared.favoritesViewController
    self.setupTabBarItem(vc: favoritesVC,
                     title: "Favorites",
                     imageName: "heart",
                     selectedImageName: "heart.fill")
    
    self.tabBarController.tabBar.barStyle = .black
    self.tabBarController.tabBar.isTranslucent = false
    self.tabBarController.tabBar.tintColor = .white
    
    self.tabBarController.viewControllers = [FirstTabCoordinator.shared.navigationController,
                                             SecondTabCoordinator.shared.navigationController]
  }
 
  func setupTabBarItem(vc: UIViewController, title: String, imageName: String, selectedImageName: String) {
    let defaultImage = UIImage(systemName: imageName)
    let selectedImage = UIImage(systemName: selectedImageName)
    let tabBarItem = UITabBarItem(title: title, image: defaultImage, selectedImage: selectedImage)
    vc.tabBarItem = tabBarItem
  }
}

First Tab coordinator:

class FirstTabCoordinator: Coordinator {
  var navigationController: UINavigationController! {
    didSet {
      navigationController?.navigationBar.tintColor = .white
      navigationController?.navigationBar.barStyle = .black
    }
  }
  let storyboard = UIStoryboard(name: "Main", bundle: .main)
  private lazy var navigationManager = NavigationManager(self.navigationController)
  
  static let shared = FirstTabCoordinator()
  private init() {}
  
  lazy var moviesListViewController: MoviesTableViewController = {
    let viewController = self.storyboard.instantiateViewController(identifier: "MoviesTableViewController") as! MoviesTableViewController
    viewController.title = "All Movies"
    return viewController
  }()
  
  func startCoordinator() {
    self.navigationController = UINavigationController()
    self.navigationController.viewControllers = [self.moviesListViewController]
  }
  
  func goToMovieDetails(movie: Movie) {
    self.navigationManager.goToMovieDetails(movie: movie)
  }
}

Second Tab Coordinator:

class SecondTabCoordinator: Coordinator {
  var navigationController: UINavigationController! {
    didSet {
      navigationController?.navigationBar.tintColor = .white
      navigationController?.navigationBar.barStyle = .black
    }
  }
  let storyboard = UIStoryboard(name: "Main", bundle: .main)
  private lazy var navigationManager = NavigationManager(self.navigationController)

  static let shared = SecondTabCoordinator()
  private init() {}
  
  lazy var favoritesViewController: FavoritesViewController = {
    let viewController = self.storyboard.instantiateViewController(identifier: "FavoritesViewController") as FavoritesViewController
    viewController.title = "Favorites"
    return viewController
  }()
  
  func goToMovieDetails(movie: Movie) {
    self.navigationManager.goToMovieDetails(movie: movie)
  }
  
  func startCoordinator() {
    self.navigationController = UINavigationController()
    self.navigationController.viewControllers = [self.favoritesViewController]
  }
}

CodePudding user response:

You can just make the coordinator implement a protocol that contains your function func goToMovieDetails(movie: Movie) and pass in an instance of it when creating the ViewController so you don't care if it is First or Second Tab coordinator

  • Related