Swift - 从 UITableView 中嵌入的 UICollectionView 访问数据的问题

Posted

技术标签:

【中文标题】Swift - 从 UITableView 中嵌入的 UICollectionView 访问数据的问题【英文标题】:Swift - Issue accessing data from UICollectionView embedded in UITableView 【发布时间】:2020-04-09 01:21:36 【问题描述】:

我有一个 tableView,它的原型单元格包含一个 UICollectionView。我已经根据本教程 (https://medium.com/@stasost/ios-how-to-build-a-table-view-with-multiple-cell-types-2df91a206429) 设置了 tableView,并且 UI 可以正常工作。我可以通过我的 tableView 将数据传递到 collectionView 中。

View Layout

When a collectionViewCell is selected it segues to another view.

我还没有弄清楚如何从 collectionViewCell 访问数据并将其传递给新视图。

collectionView 在 tableView 原型单元格中初始化。我已经尝试过 didSelectRow -> prepareForSegue(代码如下),但命令不会自动完成,并且无法正常工作。

这是 tableViewCell 的代码,其中设置了 collectionView。


编辑:为清楚起见删除了注释代码

import UIKit

class homeFeedTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource 

    @IBOutlet weak var feedCollectionView: UICollectionView!
    var selectedEvent : Event? 

    var collectionItems = [CollectionViewModelItem]()
    var collectionItem : CollectionViewModelItem?

    @IBOutlet weak var sectionHeadingLabel: UILabel!
    override func awakeFromNib() 
        super.awakeFromNib()
        // Initialization code

        feedCollectionView.delegate = self
        feedCollectionView.dataSource = self

        print("collection items \(collectionItems.count)")
        for item in collectionItemsprint("type: \(item.type), title: \(item.eventTitle)")

    

    override func setSelected(_ selected: Bool, animated: Bool) 
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    

    //    setup view model
      var item: TableViewModelItem? 
                didSet 
    //                if not right class, skip
                    guard let item = item as? TableViewModelFeed else 
                        return
                    
                    sectionHeadingLabel.text = item.sectionTitle
                
            

    //    create reuse identifier property
            static var identifier: String 
                return String(describing: self)
            






import Foundation
import UIKit

extension homeFeedTableViewCell 

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
//    print("dataCount3: \(collectionItems.count) \(collectionItems[collectionItems.count-1].type)")
    return collectionItems.count


func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
//    let cell = UICollectionViewCell()
//    return cell

    self.collectionItem = collectionItems[indexPath.row]

    switch collectionItem!.type 
    case .yourEvents:
        if let cell = collectionView.dequeueReusableCell(withReuseIdentifier:YourEventsCollectionViewCell.identifier, for: indexPath) as? YourEventsCollectionViewCell

            cell.item = collectionItem
            print(cell.item?.type)
            print(".yourEvents")
            return cell
        
    case .feed:
        if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: mainFeedCollectionViewCell.identifier, for: indexPath) as? mainFeedCollectionViewCell
            cell.item = collectionItem
            print(".feed")

            return cell
        
    
    return UICollectionViewCell()



    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
        print("\(collectionItems[indexPath.row].eventTitle) tapped")

        func prepare(for segue: UIStoryboardSegue, sender: Any?) 
            if segue.identifier == "yourEventsToEventViewController" || segue.identifier == "feedToEventViewController"
                print("prepare for segue1")
                let destinationVC = segue.destination as! EventViewController
                if collectionItem != nil
                    print("prepare for segue2")
                    destinationVC.backgroundImageUrl = collectionItem!.backgroundImageUrl
                
            
        


    


【问题讨论】:

【参考方案1】:

UICollectionView 使用属性indexPathsForSelectedItems 跟踪其选定的 indexPaths。由于您在collectionView(didSelectItem: atIndexPath:) 中触发了segue,因此您选择的indexPath 在prepare(forSegue:) 期间可用。您可以尝试以下方法:

class MyViewController: UIViewController, UICollectionViewDelegate 

    ...

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
        performSegue(withIdentifier: "mySegue", sender: self)
    

    ...

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        super.prepare(for: segue, sender: sender)

        guard let destinationVC = segue.destination as! EventViewController,
            segue.identifier == "mySegue" else  return 

        // In this context, your selected cell is the one who fired the segue

        if let selectedIndexPaths = collectionView.indexPathsForSelectedItems,
            let firstSelectedIndexPath = selectedIndexPaths.first 

            let selectedObject = collectionItems[firstSelectedIndexPath.row]

            destinationVC?.backgroundUrl = selectedObject.backgroundUrl
        
    

顺序是:

    您选择一个单元格(通过用户交互,即点击)。 didSelect 执行名为“mySegue”的转场(在本例中)。 在prepareForSegue 中,查找您选择的索引路径。假设你没有使用多选,你想要你的第一个也是唯一的 indexPath。使用该索引路径,您可以检索 collectionItems 数组中的数据。

【讨论】:

感谢您的建议!我能够按照建议使用 indesPath 清理选定的对象,但是 performSegue() 和 prepare(for segue) 函数不可用,因为我的 UICollectionViewDelegate 属于 UITableViewCell 类,而不是 UIViewController。我可以使用主视图控制器中的功能,但我不知道如何从 viewController 级别访问我的 TableViewCell -> collectionViewCell 中的信息。有什么建议吗? 知道了。还没有机会重温。今天晚些时候我会想出一个更好的回应。 一个快速的想法是让你的collectionViewCell 中的一个委托回到你的视图控制器。 UIView 就是这样 - UI。它们并不意味着直接控制导航之类的东西,所以它们不能执行 segue 或类似的东西。这个责任属于UIViewController,所以不知何故,你必须在那里处理电话。

以上是关于Swift - 从 UITableView 中嵌入的 UICollectionView 访问数据的问题的主要内容,如果未能解决你的问题,请参考以下文章

Swift:使用 prepareForSegue 将 UIView 容器的高度设置为嵌入式 UITableView 的高度

如何从嵌入在 UITableViewCell (Swift) 中的 UICollectionView 的单元格中分离出来?

嵌入在容器中的 UITableView 不刷新

Swift:数组、文本字段和 UITableView

Swift 3:由于 UINavigationViewController 导致 UITableView 行高发生变化

为啥嵌入 UINavigationController 时不再显示 UITableView