同一ViewController中多UICollectionView点击Cell传Movie对象至详情页问题
嘿,我来帮你搞定这个问题!你现在的情况是主VC里有4个套在容器视图里的UICollectionView,要把选中的Movie对象传到详情页对吧?其实核心是要先找到点击的Cell属于哪个CollectionView,再对应到对应的数据源数组,最后把对象传过去。下面分步骤给你讲清楚:
解决容器视图中UICollectionView的Movie对象传递问题
步骤1:给每个CollectionView设置唯一标记
首先得给4个UICollectionView分别加个独一无二的tag,这样咱们能区分开它们。比如在容器视图的子ViewController里(或者你管理这些CollectionView的地方),给它们赋值:
// 假设这四个是你容器里的CollectionView实例 collectionViewPlaying.tag = 1001 collectionViewPopular.tag = 1002 collectionViewUpcoming.tag = 1003 collectionViewTopRated.tag = 1004
步骤2:在prepare方法里定位选中的Movie对象
在主ViewController的prepare(for:sender:)方法里,sender其实就是被点击的UICollectionViewCell,咱们可以通过它反向找到所属的CollectionView,再根据tag匹配对应的数据源数组,拿到选中的Movie:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // 先把sender转成UICollectionViewCell,确保不是空值 guard let tappedCell = sender as? UICollectionViewCell else { return } // 从Cell往上找它所属的UICollectionView var targetCollectionView: UICollectionView? var currentView = tappedCell.superview while currentView != nil { if let cv = currentView as? UICollectionView { targetCollectionView = cv break } currentView = currentView?.superview } guard let collectionView = targetCollectionView else { return } var selectedMovie: Movie? // 根据tag判断对应的数据源数组,拿到选中的Movie switch collectionView.tag { case 1001: let indexPath = collectionView.indexPath(for: tappedCell)! selectedMovie = playingMoviesArray[indexPath.item] case 1002: let indexPath = collectionView.indexPath(for: tappedCell)! selectedMovie = popularMoviesArray[indexPath.item] case 1003: let indexPath = collectionView.indexPath(for: tappedCell)! selectedMovie = upcomingMoviesArray[indexPath.item] case 1004: let indexPath = collectionView.indexPath(for: tappedCell)! selectedMovie = topRatedMoviesArray[indexPath.item] default: break } // 把Movie对象传给详情页 if segue.identifier == "MovieDetailsPlaying" { let detailVC = segue.destination as! MovieDetailsViewController detailVC.selectedMovie = selectedMovie } }
更优雅的优化方案(可选)
如果每个容器视图都有自己的子ViewController,那可以把选中逻辑放到子VC里,用闭包回调给主VC,代码结构会更清晰:
第一步:在容器子VC里设置回调
// 定义一个闭包,用来传递选中的Movie var didSelectMovie: ((Movie) -> Void)? // 处理CollectionView的选中事件 override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let selectedMovie = yourLocalDataSourceArray[indexPath.item] // 触发回调,把Movie传给主VC didSelectMovie?(selectedMovie) // 也可以直接在这里触发Segue,前提是Segue是从子VC连到详情页 performSegue(withIdentifier: "MovieDetailsPlaying", sender: selectedMovie) } // 子VC里的prepare方法直接传值 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "MovieDetailsPlaying" { let detailVC = segue.destination as! MovieDetailsViewController detailVC.selectedMovie = sender as? Movie } }
第二步:主VC里接收回调
// 假设你在主VC里初始化容器子VC的时候 func setupContainerViewControllers() { let playingVC = storyboard?.instantiateViewController(withIdentifier: "PlayingMoviesVC") as! PlayingMoviesVC // 设置回调,拿到选中的Movie后跳转到详情页 playingVC.didSelectMovie = { [weak self] movie in self?.performSegue(withIdentifier: "MovieDetailsPlaying", sender: movie) } // 把playingVC添加到容器视图中... }
这样每个子VC自己管理自己的数据源和选中逻辑,主VC只需要处理跳转,代码耦合度更低~
内容的提问来源于stack exchange,提问作者Ruben Aalders
相关产品推荐
相关产品推荐

