본문 바로가기
Project/NETFLIX

넷플릭스 앱 클론 11편 (영화 상세페이지)

by 밤새는탐험가 2024. 5. 16.

✅ 영화 상세 페이지 제작 

  • 상세 페이지 생성
  • 상세 페이지에 전달하기 위한 ViewModel 생성 
  • 상세 페이지에 데이터를 전달하는 함수 구현
  • 데이터 전달을 위한 델리게이트 패턴 적용

✅ 영화 상세 페이지 제작 

  • TitlePreviewViewController 파일 생성 
  • Home 화면에서 영화를 누르면 해당 영화에 대한 예고편과 영화 이름 그리고 개요가 나오게 함 
import UIKit
import WebKit


class TitlePreviewViewController: UIViewController {
    
    
    private let webView: WKWebView = {
        let webView = WKWebView()
        webView.translatesAutoresizingMaskIntoConstraints = false
        return webView
    }()
    
    
    private let titleLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = .systemFont(ofSize: 22, weight: .bold)
        label.text = "Harry Potter"
        return label
    }()
    
    
    private let overviewLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = .systemFont(ofSize: 18, weight: .bold)
        label.numberOfLines = 0
        label.text = "This is the best movie "
        return label
    }()
    

    private let downloadButton: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = .red
        button.setTitle("Download", for: .normal)
        button.setTitleColor(.label, for: .normal)
        button.layer.cornerRadius = 10
        button.layer.masksToBounds = true
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        
        
        view.addSubview(webView)
        view.addSubview(titleLabel)
        view.addSubview(overviewLabel)
        view.addSubview(downloadButton)
        
        
        configureConstraints()
    }
    
    func configureConstraints() {
        
        let webViewConstraints = [
            webView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50),
            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            webView.heightAnchor.constraint(equalToConstant: 250)
        ]
        
        let titleLabelConstraints = [
            titleLabel.topAnchor.constraint(equalTo: webView.bottomAnchor, constant: 20),
            titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20)
        ]
        
        let overviewLabelConstraints = [
            overviewLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15),
            overviewLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20)
        ]
            
        let downloadButtonConstraints = [
            downloadButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            downloadButton.topAnchor.constraint(equalTo: overviewLabel.bottomAnchor, constant: 25),
            downloadButton.widthAnchor.constraint(equalToConstant: 140),
            downloadButton.heightAnchor.constraint(equalToConstant: 40)
        ]
        
        NSLayoutConstraint.activate(webViewConstraints)
        NSLayoutConstraint.activate(titleLabelConstraints)
        NSLayoutConstraint.activate(overviewLabelConstraints)
        NSLayoutConstraint.activate(downloadButtonConstraints)
    }
}

 

 

  • ViewModel 폴더 내에 TitlePreviewViewModel 이라는 데이터 모델 생성
import Foundation


struct TitlePreviewViewModel {
    
    
    let title: String
    let youtubeView: VideoElement
    let titleOverview: String
    
    
}

 

 

  • TitlePreviewViewController 내에 데이터를 받아올 함수 구현 
    // 데이터 불러오기
    func configure(with model: TitlePreviewViewModel) {
        titleLabel.text = model.title
        overviewLabel.text = model.titleOverview
        
        guard let url = URL(string:"http://www.youtube.com/embed/\(model.youtubeView.id.videoId)") else { return }
        
        webView.load(URLRequest(url: url))
    
    }

 

 

  • CollectionViewTableViewCell 파일에 프로토콜 생성 
  • 델리게이트 패턴을 사용하여 데이터 전달 목적
protocol CollectionViewTableViewCellDelegate: AnyObject {
    func CollectionViewTableViewCellDidTapCell(_ cell: CollectionViewTableViewCell, viewModel: TitlePreviewViewModel)
}

 

 

  • 대리자 변수 선언 
class CollectionViewTableViewCell: UITableViewCell {
    
    static let identifier = "CollectionViewTableViewCell"
    
    
    // 데이터 전달을 위한 대리자 선언
    weak var delegate: CollectionViewTableViewCellDelegate?

 

 

  • collectionView 내의 세을 선택하면 결과를 반영하는 함수 구현 
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        collectionView.deselectItem(at: indexPath, animated: true)
        
        let title = titles[indexPath.row]
        guard let titleName = title.original_title ?? title.original_name else { return }
        
        
        APICaller.shared.getMovie(with: titleName + " trailer") { result in
            switch result {
            case .success(let videoElement):
                
                
                let title = self.titles[indexPath.row]
                guard let titleOverview = title.overview else { return }
                
                let viewModel = TitlePreviewViewModel(title: titleName, youtubeView: videoElement, titleOverview: titleOverview)
                
                self.delegate?.CollectionViewTableViewCellDidTapCell(self, viewModel: viewModel)
                
            case .failure(let error):
                print(error.localizedDescription)
            }
        }
    }

 

 

  • 홈뷰컨트롤러에서 데이터를 불러오는 함수구현 
extension HomeViewController: CollectionViewTableViewCellDelegate {
    func CollectionViewTableViewCellDidTapCell(_ cell: CollectionViewTableViewCell, viewModel: TitlePreviewViewModel) {
        
        DispatchQueue.main.async { [weak self] in
            let vc = TitlePreviewViewController()
            vc.configure(with: viewModel)
            self?.navigationController?.pushViewController(vc, animated: true)
        }
    }
}

 

  • TitlePreviewViewController 내에 delegate 라는 변수에 접근하기 위해 cell 에 접근이 가능한 tableView 메서드에 접근
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
    
    // 전체 셀 갯수
    func numberOfSections(in tableView: UITableView) -> Int {
        return sectionTitles.count
    }
    
    
    // 각 셀에 들어갈 셀의 갯수 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        guard let cell = tableView.dequeueReusableCell(withIdentifier: CollectionViewTableViewCell.identifier, for: indexPath) as? CollectionViewTableViewCell else { return UITableViewCell() }
        
        cell.delegate = self

 

 

https://youtu.be/Wg19HLoG6ac?si=9lzlEctmMopI4X3Q

 

 

\