iosswiftviewcontrolleraddsubview

Adding two view controller content into single view


I am trying add two view controller content into single view. Here How I am trying to do it . First create one single view controller and then add the require view into private function then call into viewDidLoad function.

Here is the code..


import UIKit

class CommonViewController: UIViewController {
    
    private let viewModel: MoviesDetailsViewModel

    init(viewModel: MoviesDetailsViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
        navigationItem.largeTitleDisplayMode = .never
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

         combineView()
        navigationItem.leftBarButtonItem = UIBarButtonItem.backButton(target: self, action: #selector(didTapBack(_:)))
    }
    
    private func combineView() {
        let dvc = MovieDetailsViewController(viewModel: viewModel)
        let svc = SmiliarMovieViewController(viewModel: viewModel)
        view.addSubview(dvc.view)
        view.addSubview(svc.view)
        
    }
    @objc private func didTapBack(_ sender: UIBarButtonItem) {
        navigationController?.popViewController(animated: true)
    }
}

I am calling this CommonViewController into didSelectRowAt function here is code for it.

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let movie = viewModel.state.movies[indexPath.row]
        let viewModel = MoviesDetailsViewModel(movie: movie, apiManager: APIManager())
        let com  = CommonViewController(viewModel: viewModel)
        self.navigationController?.pushViewController(com, animated: true)

    }

The problem is when I select the table view cell , I am expecting the show the details of the selected cell but it not rendering the view content. Please note that when I try to call DetailsViewController (specific view controller ) it is able show the content.

Here is the screenshot ..

Error on adding constraints ..

enter image description here

enter image description here


Solution

  • This pattern is called a container view controller, where the current view controller is a “container” for “child” view controllers. You are likely familiar with the hierarchy of views, but there is a similar view controller hierarchy that mirrors that of the views.

    So, consider your combineView:

    private func combineView() {
        let dvc = MovieDetailsViewController(viewModel: viewModel)
        let svc = SmiliarMovieViewController(viewModel: viewModel)
        view.addSubview(dvc.view)
        view.addSubview(svc.view)
    }
    

    You need to call addChild(_:) to tell the current view controller that it has a child view controller. And when you are done adding the child view controller’s views to the view hierarchy, you have to let it know when you are done doing that by calling didMove(toParent:). E.g.:

    private func combineView() {
        let dvc = MovieDetailsViewController(viewModel: viewModel)
        addChild(dvc)
        dvc.view.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(dvc.view)
    
        let svc = SmiliarMovieViewController(viewModel: viewModel)
        addChild(svc)
        svc.view.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(svc.view)
    
        NSLayoutConstraint.activate([
            dvc.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            dvc.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            dvc.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
    
            svc.view.topAnchor.constraint(equalTo: dvc.view.bottomAnchor),
    
            svc.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
            svc.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            svc.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
    
            dvc.view.heightAnchor.constraint(equalTo: svc.view.heightAnchor)
        ])
    
        dvc.didMove(toParent: self)
        svc.didMove(toParent: self)
    }
    

    A few observations:


    FWIW, I have posted an example of a container view controller in this GitHub repo, resulting in:

    example