Saturday, February 24, 2024
HomeiOS Developmentios - Navigating One view to a different view kind tableview didselect...

ios – Navigating One view to a different view kind tableview didselect operate unable to show the end result


I’ve tried completely different strategy to get the anticipated end result however it actually not working. Right here is the use case . Once I choose the desk view cell and I’m anticipating to indicate chosen cell particulars into particulars view controller and on the identical time making API name to get the associated information . The associated information id (Film ID) will come kind desk view cell. I’m making an attempt to mix each view content material as youngster view.

Right here is the did choose operate code ..

// MARK: - UITableViewControllerDelegate
extension MoviesViewController {

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let film = viewModel.state.motion pictures[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 information.**
        self.navigationController?.pushViewController(viewController, animated: true)
    }
}

Right here is the view mannequin code get the end result and retailer into native variable .. Right here func fetchSimilarMovie()making API name and get the info 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
        }
    }
}

ultimate 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] lead to
            guard let self = self else { return }
            swap end result {
            case .success(let movieDetails):
                self.state = .loaded(movieDetails)
            case .failure:
                self.state = .error
            }
        }
    }
    
    func fetchSimilarMovie() {
        apiManager.execute(Film.similiar(for: initialMovie.id)) { [weak self]  lead to
            guard let self = self else { return }
            swap end result {
            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 completely 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 ..

ultimate 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 applied")
    }

    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.predominant.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,
            length: 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,
            length: 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..

ultimate 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 applied")
    }
    
    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(prime: 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 applied")
    }
    
    fileprivate let collectionView:UICollectionView = {
        let structure = UICollectionViewFlowLayout()
        structure.scrollDirection = .horizontal
        let cv = UICollectionView(body: .zero, collectionViewLayout: structure)
        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.predominant.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, structure collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.body.width/2.5, peak: collectionView.body.width/2)
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection part: Int) -> Int {
    let gadgets = viewModel.moviePage.rely
    return gadgets
    }
    
    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.

ultimate class MovieCell: UITableViewCell {
    
    let columnSpacing: CGFloat = 16
    let posterSize = CGSize(width: 92, peak: 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(prime: 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 = .prime
        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 end result after I run the app..

initial app result

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

enter image description here

Right here is the end result after I choose completely different cell .. It exhibiting empty assortment view no information.

empty collection view



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments