HomeiOS Developmentios - Navigating One view to a different view type tableview didselect...

ios – Navigating One view to a different view type tableview didselect perform unable to show the outcome


I’ve tried totally different strategy to get the anticipated outcome but it surely actually not working. Right here is the use case . After I choose the desk view cell and I’m anticipating to point out chosen cell particulars into particulars view controller and on the identical time making API name to get the associated knowledge . The associated knowledge id (Film ID) will come type desk view cell. I’m making an attempt to mix each view content material as youngster view.

Right here is the did choose perform code ..

// MARK: - UITableViewControllerDelegate
extension MoviesViewController {

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let film = viewModel.state.films[indexPath.row]
        let viewModel = MoviesDetailsViewModel(film: film, apiManager: APIManager())
        let viewController = MovieDetailsViewController(viewModel: viewModel)
        viewModel.fetchSimilarMovie() **// right here making API for to get related film knowledge.**
        self.navigationController?.pushViewController(viewController, animated: true)
    }
}

Right here is the view mannequin code get the outcome and retailer into native variable .. Right here func fetchSimilarMovie()making API name and get the information and retailer into var moviePage = [Movie]()

enum MoviesDetailsViewModelState {
    case loading(Film)
    case loaded(MovieDetails)
    case pageLoaded(Web page<Film>)
    case error

    var title: String? {
        swap self {
        case .loaded(let film):
            return film.title
        case .loading(let film):
            return film.title
        case .error:
            return nil
        case .pageLoaded:
            return nil
        }
    }

    var film: MovieDetails? {
        swap self {
        case .loaded(let film):
            return film
        case .loading, .error:
            return nil
        case .pageLoaded:
            return nil
        }
    }
    
    var web page: Web page<Film>? {
        
        swap self {
        case .loading, .error, .loaded:
            return nil
        case .pageLoaded(let web page):
          return web page
        }
    }
}

closing class MoviesDetailsViewModel {

    personal let apiManager: APIManaging
    personal let initialMovie: Film
    var moviePage = [Movie]()

    init(film: Film, apiManager: APIManaging = APIManager()) {
        self.initialMovie = film
        self.apiManager = apiManager
        self.state = .loading(film)
    }

    var updatedState: (() -> Void)?

    var state: MoviesDetailsViewModelState {
        didSet {
            updatedState?()
        }
    }

    func fetchData() {
        apiManager.execute(MovieDetails.particulars(for: initialMovie)) { [weak self] end in
            guard let self = self else { return }
            swap outcome {
            case .success(let movieDetails):
                self.state = .loaded(movieDetails)
            case .failure:
                self.state = .error
            }
        }
    }
    
    func fetchSimilarMovie() {
        apiManager.execute(Film.similiar(for: initialMovie.id)) { [weak self]  end in
            guard let self = self else { return }
            swap outcome {
            case.success(let web page):
                self.state = .pageLoaded(web page)
                self.moviePage = web page.outcomes
                print(moviePage)
            case .failure(let error):
                self.state = .error
                print(error)
            }
        }
    }
}

Right here is the MovieDetailsViewController the place I’ve totally different state to show the content material.. The personal func showMovieDetails(_ movieDetails: MovieDetails) right here I’m creating container for 3 views and add it as youngster view ..

closing class MovieDetailsViewController: UIViewController {

    personal let viewModel: MoviesDetailsViewModel
    personal var currentViewController: UIViewController!
    
    init(viewModel: MoviesDetailsViewModel) {
        self.viewModel = viewModel
        tremendous.init(nibName: nil, bundle: nil)
        navigationItem.largeTitleDisplayMode = .by no means
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been carried out")
    }

    override func viewDidLoad() {
        tremendous.viewDidLoad()
        navigationItem.leftBarButtonItem = UIBarButtonItem.backButton(goal: self, motion: #selector(didTapBack(_:)))
        updateFromViewModel()
        bindViewModel()
        viewModel.fetchData()
    }

    personal func bindViewModel() {
        viewModel.updatedState = { [weak self] in
            guard let self else { return }
            DispatchQueue.essential.async {
                self.updateFromViewModel()
            }
        }
    }

    personal func updateFromViewModel() {
        let state = viewModel.state
        title = state.title
        swap state {
        case .loading(let film):
            self.showLoading(film)
        case .loaded(let particulars):
            self.showMovieDetails(particulars)
        case .error:
            self.showError()
        case .pageLoaded(let web page):
            self.showSimiliarMovieDetails(web page)
        }
    }

    personal func showLoading(_ film: Film) {
        let loadingViewController = LoadingViewController()
        addChild(loadingViewController)
        loadingViewController.view.body = view.bounds
        loadingViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(loadingViewController.view)
        loadingViewController.didMove(toParent: self)
        currentViewController = loadingViewController
    }

    personal func showMovieDetails(_ movieDetails: MovieDetails) {
        let containerView = UIViewController()
        let displayViewController = MovieDetailsDisplayViewController(movieDetails: movieDetails)
        let smiliarMovieViewController = SmiliarMovieViewController(viewModel: viewModel)
        containerView.addChild(smiliarMovieViewController)
        containerView.addChild(displayViewController)
        let loadingViewController = LoadingViewController()
        containerView.addChild(loadingViewController)
        containerView.willMove(toParent: nil)
        addChild(containerView)
        transition(
            from: currentViewController,
            to: containerView,
            period: 0.25,
            choices: [.transitionCrossDissolve],
            animations: nil
        ) { (_) in
            self.currentViewController.removeFromParent()
            self.currentViewController = containerView
            self.currentViewController.didMove(toParent: self)
        }
    }
    
    personal func showSimiliarMovieDetails(_ similiarMovieDetails: Web page<Film>) {
        let smiliarMovieViewController = SmiliarMovieViewController(viewModel: viewModel)
        addChild(smiliarMovieViewController)
        smiliarMovieViewController.view.body = view.bounds
        smiliarMovieViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        currentViewController?.willMove(toParent: nil)
        transition(
            from: currentViewController,
            to: smiliarMovieViewController,
            period: 0.25,
            choices: [.transitionCrossDissolve],
            animations: nil
        ) { (_) in
            self.currentViewController.removeFromParent()
            self.currentViewController = smiliarMovieViewController
            self.currentViewController.didMove(toParent: self)
        }
    }
}

Right here is the code for MovieDetailsDisplayViewController. I’m following programmatic strategy to create the view..

closing class MovieDetailsDisplayViewController: UIViewController {
    
    let movieDetails: MovieDetails
   
    init(movieDetails: MovieDetails) {
        self.movieDetails = movieDetails
        tremendous.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been carried out")
    }
    
    override func loadView() {
        view = ParentView()
    }
    
    override func viewDidLoad() {
        tremendous.viewDidLoad()
        
         view = ParentView()
        (view as? ParentView)?.configure(movieDetails: movieDetails)
    }
    
    personal class ParentView: UIView {
        
        let scrollView = UIScrollView()
        let backdropImageView = UIImageView()
        let titleLabel = UILabel()
        let overviewLabel = UILabel()
        let similarLabel = UILabel()
        personal lazy var contentStackView = UIStackView(arrangedSubviews: [backdropImageView, titleLabel, overviewLabel, similarLabel])
        
        override init(body: CGRect) {
            tremendous.init(body: body)
            commonInit()
        }
        
        required init?(coder aDecoder: NSCoder) {
            tremendous.init(coder: aDecoder)
            commonInit()
        }
        
        personal func commonInit() {
            backgroundColor = .white
            
            backdropImageView.contentMode = .scaleAspectFill
            backdropImageView.clipsToBounds = true
            
            titleLabel.font = UIFont.Heading.medium
            titleLabel.textColor = UIColor.Textual content.charcoal
            titleLabel.numberOfLines = 0
            titleLabel.lineBreakMode = .byWordWrapping
            titleLabel.setContentHuggingPriority(.required, for: .vertical)
            
            overviewLabel.font = UIFont.Physique.small
            overviewLabel.textColor = UIColor.Textual content.gray
            overviewLabel.numberOfLines = 0
            overviewLabel.lineBreakMode = .byWordWrapping
            
            similarLabel.font = UIFont.Physique.smallSemiBold
            similarLabel.textColor = UIColor.Textual content.charcoal
            similarLabel.numberOfLines = 0
            similarLabel.lineBreakMode = .byWordWrapping
            
            contentStackView.axis = .vertical
            contentStackView.spacing = 24
            contentStackView.setCustomSpacing(8, after: titleLabel)
            
            setupViewsHierarchy()
            setupConstraints()
        }
        
        personal func setupViewsHierarchy() {
            addSubview(scrollView)
            scrollView.addSubview(contentStackView)
        }
        
        personal func setupConstraints() {
            scrollView.translatesAutoresizingMaskIntoConstraints = false
            backdropImageView.translatesAutoresizingMaskIntoConstraints = false
            contentStackView.translatesAutoresizingMaskIntoConstraints = false
            
            NSLayoutConstraint.activate(
                [
                    scrollView.topAnchor.constraint(equalTo: topAnchor),
                    scrollView.leadingAnchor.constraint(equalTo: leadingAnchor),
                    scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
                    scrollView.trailingAnchor.constraint(equalTo: trailingAnchor),
                    
                    contentStackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 24),
                    contentStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
                    contentStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
                    contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -24)
                ]
            )
            
            scrollView.layoutMargins = UIEdgeInsets(high: 24, left: 16, backside: 24, proper: 16)
            preservesSuperviewLayoutMargins = false
        }
        
        func configure(movieDetails: MovieDetails) {
            backdropImageView.dm_setImage(backdropPath: movieDetails.backdropPath)
            
            titleLabel.textual content = movieDetails.title
            
            overviewLabel.textual content = movieDetails.overview
        }
    }
}

Right here is the code for SmiliarMovieViewController.

class SmiliarMovieViewController: UIViewController, UICollectionViewDelegate {

    personal let viewModel: MoviesDetailsViewModel

    init(viewModel: MoviesDetailsViewModel) {
        self.viewModel = viewModel
        tremendous.init(nibName: nil, bundle: nil)
        navigationItem.largeTitleDisplayMode = .by no means
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been carried out")
    }
    
    fileprivate let collectionView:UICollectionView = {
        let format = UICollectionViewFlowLayout()
        format.scrollDirection = .horizontal
        let cv = UICollectionView(body: .zero, collectionViewLayout: format)
        cv.translatesAutoresizingMaskIntoConstraints = false
        cv.register(SimilierMovieCell.self, forCellWithReuseIdentifier: "CompanyCell")
        cv.backgroundColor = .lightGray

        return cv
    }()
   
    override func viewDidLoad() {
        tremendous.viewDidLoad()
        setUpUI()
        self.viewModel.updatedState = {[weak self] in
            DispatchQueue.essential.async {
                self?.collectionView.reloadData()
            }
        }
        viewModel.fetchSimilarMovie()
    }
    
    personal func setUpUI() {
        view.addSubview(collectionView)
        collectionView.topAnchor.constraint(equalTo: view.topAnchor, fixed: 40).isActive = true
        collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, fixed: 40).isActive = true
        collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, fixed: -40).isActive = true
        collectionView.heightAnchor.constraint(equalToConstant: view.body.width/2).isActive = true
    }
}

extension SmiliarMovieViewController: UICollectionViewDataSource {
    
    func collectionView(_ collectionView: UICollectionView, format collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.body.width/2.5, top: collectionView.body.width/2)
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection part: Int) -> Int {
    let objects = viewModel.moviePage.depend
    return objects
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SimilierMovieCell.identifier, for: indexPath) as? SimilierMovieCell
        
        let listMovie = viewModel.moviePage[indexPath.row]
        print(listMovie)
        cell?.configure(listMovie)
        return cell ?? SimilierMovieCell()
    }
}

Right here is the cell code .. Similar code I’ve reused for assortment view cell.

closing class MovieCell: UITableViewCell {
    
    let columnSpacing: CGFloat = 16
    let posterSize = CGSize(width: 92, top: 134)
    
    let coverImage = UIImageView()
    let tagView = TagView()
    let titleLabel = UILabel()
    let descriptionLabel = UILabel()
    
    let textStackView = UIStackView()
    let imageStackView = UIStackView()
    let containerStackView = UIStackView()
    
    override init(fashion: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        tremendous.init(fashion: fashion, reuseIdentifier: reuseIdentifier)
        commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        tremendous.init(coder: aDecoder)
        commonInit()
    }
    
    personal func commonInit() {
        layoutMargins = UIEdgeInsets(high: 16, left: 16, backside: 16, proper: 16)
        titleLabel.font = UIFont.Heading.small
        titleLabel.textColor = UIColor.Textual content.charcoal
        titleLabel.numberOfLines = 0
        titleLabel.lineBreakMode = .byWordWrapping
        
        descriptionLabel.font = UIFont.Physique.small
        descriptionLabel.textColor = UIColor.Textual content.gray
        descriptionLabel.numberOfLines = 0
        descriptionLabel.lineBreakMode = .byWordWrapping
        
        coverImage.contentMode = .scaleAspectFit
        coverImage.layer.cornerRadius = 8
        coverImage.layer.masksToBounds = true
        
        textStackView.spacing = 4
        textStackView.alignment = .main
        textStackView.axis = .vertical
        
        imageStackView.spacing = 10
        imageStackView.alignment = .main
        imageStackView.axis = .vertical
        
        containerStackView.spacing = columnSpacing
        containerStackView.alignment = .high
        containerStackView.translatesAutoresizingMaskIntoConstraints = false
        
        setupViewsHierarchy()
        setupConstraints()
    }
    
    func setupViewsHierarchy() {
        contentView.addSubview(containerStackView)
        imageStackView.dm_addArrangedSubviews(coverImage, tagView)
        textStackView.dm_addArrangedSubviews(titleLabel, descriptionLabel)
        containerStackView.dm_addArrangedSubviews(imageStackView, textStackView)
    }
    
    func setupConstraints() {
        
        NSLayoutConstraint.activate([
            containerStackView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
            containerStackView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
            containerStackView.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor),
            containerStackView.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor),
            
            coverImage.widthAnchor.constraint(equalToConstant: posterSize.width),
            coverImage.heightAnchor.constraint(equalToConstant: posterSize.height)
        ])
    }
    
    func configure(_ film: Film) {
        titleLabel.textual content = film.title
        descriptionLabel.textual content = film.overview
        tagView.configure(.score(worth: film.voteAverage))
        
        if let path = film.posterPath {
            coverImage.dm_setImage(posterPath: path)
        } else {
            coverImage.picture = nil
        }
    }
    
    override func prepareForReuse() {
        tremendous.prepareForReuse()
    }
}

Right here is the outcome after I run the app..

initial app result

Right here is the screenshot after I choose the cell .. I’m anticipating to point out the small print of cell and present the same films particulars however its nil.

enter image description here

Right here is the outcome after I choose totally different cell .. It exhibiting empty assortment view no knowledge.

empty collection view

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments