嵌套在 CollectionViewCell 中的 TableView

Posted

技术标签:

【中文标题】嵌套在 CollectionViewCell 中的 TableView【英文标题】:TableView nested in CollectionViewCell 【发布时间】:2015-08-14 22:16:25 【问题描述】:

我正在尝试制作 TableViews 的 collectionView,以便每张桌子都包含一个“团队”的玩家。 (这个想法是Players 按他们的评分同样排序,这样每支球队都会在最后。无论如何)我在用合适的球员填充桌子时遇到了一些麻烦。排序/团队制作代码工作正常,但我不知道如何从 tableView dataSource 方法中引用每个表所在的单元格,我需要用它们各自的玩家填充正确的表。如果您感到困惑,也许下面的代码会阐明我要做什么

class myCollectionViewController: UICollectionViewController, UITableViewDelegate, UITableViewDataSource 

    //MARK: Properties

    //These value are passed by the previous ViewController in PrepareForSegue
    var numberOfTeams = Int?() //2
    var team = Array<Array<Players>>() //The 2D array of Players which contains the already sorted teams

    //for right now this is my temporary solution. See below in TableView Data Source
    var collectionIndex = 0

    //MARK: UICollectionViewDataSource

    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int 
        // #warning Incomplete implementation, return the number of sections
        return 1
    

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 

        if numberOfTeams != nil
            return numberOfTeams!
        else
            return 2
    

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! myCollectionViewCell

        cell.teamTable.dataSource = self
        cell.teamTable.delegate = self
       //teamTable is a UITableView and is set as an Outlet in the CollectionViewCell. Here I'm just setting it 

        return cell
    

    //MARK: TableView DataSource

    func numberOfSectionsInTableView(tableView: UITableView) -> Int 
        return 1
    

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        //add correct amount of rows
        return team[0].count
    

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
        //reset for refresh so index won't go out of bounds of teams Array
        if collectionIndex == numberOfTeams
            collectionIndex = 0
             print("reset")
        

(这(就在上面)是失败的地方。视图将正确加载,表格按应有的方式填充。但是如果您滚动到其中一个表格的底部,将调用此方法并刷新表格再次向上滚动时显示错误的数据。代码在下面继续)

        let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! teamTableViewCell
        cell.playerName.text = team[collectionIndex][indexPath.row].name
        //playerName is a UILabel set as an outlet in the teamTableViewCell class. also, The class Player has a property "name"

        //once all players are cycled through, add 1 to collectionIndex 
        if team[collectionIndex][indexPath.row] === team[collectionIndex].last
           collectionIndex += 1

        return cell
    

如上面括号中所述,当前的实现存在问题,只是临时解决方案,因此我可以继续处理代码的其他方面。我需要的是引用tableView所在的collectionViewCell并更改行

cell.playerName.text = team[collectionIndex][indexPath.row].name

cell.playerName.text = team[--"colletionViewCellIndexHere"--][indexPath.row].name

但我不知道如何在tableview: CellForRowAtIndexPath: 方法中引用集合单元格 indexPath.item 或行

我尝试与tableView.superView 混在一起,但没有运气。任何帮助将不胜感激。提前致谢

【问题讨论】:

【参考方案1】:

做你想做的更好的方法是把管理每个表视图的责任交给一个单独的视图控制器TeamViewController。每个TeamViewController 都有自己的team 属性,即一组玩家。创建集合视图单元格时,添加新的TeamViewController 作为子视图控制器,并将其视图添加为单元格的子视图。只是不要忘记单元格重用 - 您只想向每个单元格添加 一个 TeamViewController

这样做将提供更好的逻辑分离,并使管理您的表视图更加简单。

编辑:

正确处理单元重用的示例:

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! TeamsCell
    embedTeamInTeamsCell(cell, atIndexPath: indexPath)


func embedTeamInTeamsCell(cell: TeamsCell, atIndexPath indexPath: NSIndexPath) 
    if cell.teamViewController?.team == teams[indexPath.item] 
        // The cell already has a team view controller, but it's for the wrong team – remove it
        detachTeamFromTeamsCell(cell)
    

    if cell.teamViewController == nil 
        // The cell doesn't currently have a team view controller – create a new one and add it
        let teamVC = self.storyboard?.instantiateViewControllerWithIdentifier("TeamViewController") as! TeamViewController
        addChildViewController(teamVC)
        cell.addSubview(teamVC.view)
        // ... setup constraints on the newly added subview, or set frame
        teamVC.didMoveToParentViewController(self)
        cell.teamViewController = teamVC
    


func detachTeamFromTeamsCell(cell: TeamsCell) 
    if let teamVC = cell.teamViewController 
        teamVC.willMoveToParentViewController(nil)
        cell.teamViewController = nil
        teamVC.view.removeFromSuperview()
        teamVC.removeFromParentViewController()
    

实际上,当您需要更改单元中的嵌入式团队时,最好只重用当前嵌入的 TeamViewController 实例而不是完全丢弃它们。然后,只需更改TeamViewController 上的team 属性就足以重新配置该视图控制器以显示新团队(也许您只需要在teamdidSet 属性观察器中调用tableView.reloadData - 取决于你如何组织你的课程):

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! TeamsCell
    if cell.teamViewController == nil 
        // The cell doesn't currently have a team view controller – create a new one and add it
        let teamVC = self.storyboard?.instantiateViewControllerWithIdentifier("TeamViewController") as! TeamViewController
        addChildViewController(teamVC)
        cell.addSubview(teamVC.view)
        // ... setup constraints on the newly added subview, or set frame
        teamVC.didMoveToParentViewController(self)
        cell.teamViewController = teamVC
    

    cell.teamViewController!.team = teams[indexPath.item]

class TeamViewController: UITableViewController 
    //...

    var team: Team? 
        didSet  tableView.reloadData() 
    

【讨论】:

听起来像是一个计划。总的来说,我对 swift 和编程有点菜鸟,我需要做些什么才能将这个新的TeamViewController 设置为“子视图控制器”吗?创建子TeamViewController 的一个小语法示例肯定会有所帮助。 (我认为collectionView: numberOfItemsInSection 是添加TeamViewControllers 的最佳位置,因为(据我所知)它在设置视图时只调用一次) 当然,UIViewController 上有一些包含方法,您需要在添加/删除子视图控制器时调用它们。我在another answer写了一个简单的例子,否则你可以查看the UIViewController docs中的遏制方法。 我会努力的。看起来有点先进,因为我学习 swift 的时间还不到一个月,但实施起来不应该太粗糙。感谢您的帮助和编辑 不用担心。从概念上讲,视图控制器包含对于初学者来说并不是最简单的主题,但实际上它实际上并没有太多工作,而且值得从一开始就这样做。 ios 的视图控制器编程指南从头到尾都是一个很棒的文档,但section on custom containers 可能对您特别有帮助。 是的,这是因为细胞重用。您可以完全删除它们并重新添加正确的子视图控制器,或者理想情况下,只需更改与当前嵌入的子视图控制器关联的模型(将 teamViewController.team 更改为该索引路径的正确团队)并确保您的孩子刷新本身。我在上面添加了更完整的示例来演示两者。我没有测试过,所以把它当作伪代码吧!

以上是关于嵌套在 CollectionViewCell 中的 TableView的主要内容,如果未能解决你的问题,请参考以下文章

如何访问嵌入在主UIViewController中的父collectionViewCell中的collectionView?

collectionViewCell 中的按钮不触发功能

单击 CollectionViewCell 中的按钮

如何将imageView添加到collectionViewCell中的scrollView

如何在单元格大小更改后自动调整 CollectionViewCell 中的内容大小?

从 collectionViewCell 中的 tableView 重新加载数据