I have created one container view . Here I'm adding two view controller content into single view controller. I am rendering the view based on the different state but I want to combine both view content into single view .. The code is compile but produce following error ..
Thread 1: "Children view controllers <PremierSwift.LoadingViewController: 0x100f1f1a0> and <UIViewController: 0x104850c90> must have a common parent view controller when calling -[UIViewController transitionFromViewController:toViewController:duration:options:animations:completion:]"
Here is the code I have modified..
private func showMovieDetails(_ movieDetails: MovieDetails) {
let containerView = UIViewController()
let displayViewController = MovieDetailsDisplayViewController(movieDetails: movieDetails)
let smiliarMovieViewController = SmiliarMovieViewController(viewModel: viewModel)
containerView.addChild(smiliarMovieViewController)
containerView.addChild(displayViewController)
displayViewController.view.frame = view.bounds
displayViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
smiliarMovieViewController.view.frame = view.bounds
smiliarMovieViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
containerView.willMove(toParent: nil)
transition(
from: currentViewController,
to: containerView,
duration: 0.25,
options: [.transitionCrossDissolve],
animations: nil
) { (_) in
self.currentViewController.removeFromParent()
self.currentViewController = containerView
self.currentViewController.didMove(toParent: self)
}
}
Here is the complete view controller code..
final class MovieDetailsViewController: UIViewController {
private let viewModel: MoviesDetailsViewModel
private var currentViewController: UIViewController!
init(viewModel: MoviesDetailsViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
navigationItem.largeTitleDisplayMode = .never
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem.backButton(target: self, action: #selector(didTapBack(_:)))
updateFromViewModel()
bindViewModel()
viewModel.fetchData()
}
private func bindViewModel() {
viewModel.updatedState = { [weak self] in
guard let self else { return }
DispatchQueue.main.async {
self.updateFromViewModel()
}
}
}
private func updateFromViewModel() {
let state = viewModel.state
title = state.title
switch state {
case .loading(let movie):
self.showLoading(movie)
case .loaded(let details):
self.showMovieDetails(details)
case .error:
self.showError()
case .pageLoaded(let page):
self.showSimiliarMovieDetails(page)
}
}
private func showLoading(_ movie: Movie) {
let loadingViewController = LoadingViewController()
addChild(loadingViewController)
loadingViewController.view.frame = view.bounds
loadingViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(loadingViewController.view)
loadingViewController.didMove(toParent: self)
currentViewController = loadingViewController
}
private func showMovieDetails(_ movieDetails: MovieDetails) {
let containerView = UIViewController()
let displayViewController = MovieDetailsDisplayViewController(movieDetails: movieDetails)
let smiliarMovieViewController = SmiliarMovieViewController(viewModel: viewModel)
containerView.addChild(smiliarMovieViewController)
containerView.addChild(displayViewController)
displayViewController.view.frame = view.bounds
displayViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
smiliarMovieViewController.view.frame = view.bounds
smiliarMovieViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
containerView.willMove(toParent: nil)
transition(
from: currentViewController,
to: containerView,
duration: 0.25,
options: [.transitionCrossDissolve],
animations: nil
) { (_) in
self.currentViewController.removeFromParent()
self.currentViewController = containerView
self.currentViewController.didMove(toParent: self)
}
}
private func showSimiliarMovieDetails(_ similiarMovieDetails: Page<Movie>) {
let smiliarMovieViewController = SmiliarMovieViewController(viewModel: viewModel)
addChild(smiliarMovieViewController)
smiliarMovieViewController.view.frame = view.bounds
smiliarMovieViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
currentViewController?.willMove(toParent: nil)
transition(
from: currentViewController,
to: smiliarMovieViewController,
duration: 0.25,
options: [.transitionCrossDissolve],
animations: nil
) { (_) in
self.currentViewController.removeFromParent()
self.currentViewController = smiliarMovieViewController
self.currentViewController.didMove(toParent: self)
}
}
private func showError() {
let alertController = UIAlertController(title: "", message: LocalizedString(key: "moviedetails.load.error.body"), preferredStyle: .alert)
let alertAction = UIAlertAction(title: LocalizedString(key: "moviedetails.load.error.actionButton"), style: .default, handler: nil)
alertController.addAction(alertAction)
present(alertController, animated: true, completion: nil)
}
@objc private func didTapBack(_ sender: UIBarButtonItem) {
navigationController?.popViewController(animated: true)
}
}
Here is the screenshot of the error.
