以编程方式在特定 UICollectionViewCell 内的 TableView?

Posted

技术标签:

【中文标题】以编程方式在特定 UICollectionViewCell 内的 TableView?【英文标题】:TableView inside specific UICollectionViewCell programmatically? 【发布时间】:2017-04-05 12:57:49 【问题描述】:

我正在尝试在 UICollectionViewCell 中添加一个 TableView,所以我想自己从 TableView 管理该单元格。 所以更清楚一点,如果 indexPath.row 是 2,那么我想调用我的 tableView 单元格在 collectionview indexPath.row 中。

请检查图片,我已经用红色做了我想做的事。 我使用 UICollectionViewController 和 UICollectionViewControllerFlowLayout 以编程方式创建了所有内容。

【问题讨论】:

这个截图中的 UICollectionView 在哪里? 屏幕全是UICollectionView,即使看起来不像CollectionView。 【参考方案1】:

对于那些需要它的人,我找到了解决方案:

class CustomizedCell: UICollectionViewCell, UITableViewDataSource, UITableViewDelegate 

    var tableView = UITableView()
    let cellIdentifier: String = "tableCell"

    override func layoutSubviews() 
        super.layoutSubviews()

        tableView.delegate = self
        tableView.dataSource = self

        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
    

    func numberOfSections(in tableView: UITableView) -> Int 
        return 1
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return 4
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: cellIdentifier)

        cell.textLabel?.text = "1 CUP"
        cell.detailTextLabel?.text = "Whole"

        return cell
    

然后在 CollectionView 的 viewDidLoad 方法中我这样做了:

collectionView?.register(CustomizedCell.self, forCellWithReuseIdentifier: "cell")

然后我在 UICollectionView 的 cellForRowAt indexPath 方法中这样调用:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomizedCell

    return cell

【讨论】:

我没有看到你什么时候把UITableview添加到集合单元格中? 这不是违反 MVC 模式吗?单元格不应该对数据一无所知,因为它们只是视图 @TigranIskandaryan 我猜只有当你使用 MVC 时。 :^) 那么如何将数据分配给不同collection cell中的tableview呢? @b-m-gevariya 你在 CollectionView 和 TableView 单元格的高度中如何?【参考方案2】:

您可以为该索引路径创建自定义 UICollectionView 单元格。并在单元格xib中添加一个tableview。

在自定义cell类中实现tableview的委托方法

 class CustomCollectionViewCell: UICollectionViewCell, UITableViewDataSource, UITableViewDelegate
  
    @IBOutlet var tableView: UITableView!

    override func layoutSubviews() 
    
        super.layoutSubviews()
        tableView.delegate = self
        tableView.dataSource = self
    
  

【讨论】:

这个实现能继承CollectionViewCell本身的索引吗?还是需要通过 CollectionViewDelegate 协议获取??【参考方案3】:

上述方法不适用于 MVC 模式。我建议创建一个符合 UITableViewDelegate 和 UITableViewDataSource 的 NSObject 子类。

例如:

class DataProvider: NSObject, UITableViewDelegate, UITableViewDataSource 
    
    let dataManager = DataManager()
    let reuseId = "Cell"
    
    //MARK: - DataSource Methods
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return dataManager.data.count
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: reuseId, for: indexPath)
        cell.backgroundColor = .yellow
        return cell
    
    
    //MARK: - Delegate Methods
    

现在在您的 UICollectionViewCell 子类中,您可以指定 tableView 数据源和委托属性,如下所示:

class ContainerCollectionViewCell: UICollectionViewCell 

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var collectionView: UICollectionView!
    
    let dataProvider = DataProvider()
    
    let tableView: UITableView = 
        let table = UITableView()
        table.translatesAutoresizingMaskIntoConstraints = false
        return table
    ()
    
    override func awakeFromNib() 
       super.awakeFromNib()
        
        addSubview(tableView)
        tableView.fillSuperview()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: dataProvider.reuseId)
        tableView.delegate = dataProvider
        tableView.dataSource = dataProvider
    

也许并不完美,但实现了比上述答案更好的封装。

【讨论】:

【参考方案4】:

我找到了适合我的解决方案。

import UIKit

class FirstCollectionViewCell: UICollectionViewCell 
    
    let cellId = "cellId"
    
    let tableView:UITableView = 
        let tableView = UITableView()
        tableView.translatesAutoresizingMaskIntoConstraints = false
        return tableView
    ()
    
    override init(frame: CGRect) 
        super.init(frame: frame)
        backgroundColor = .blue
        
        addSubview(tableView)
        setUpViews()
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":tableView]))
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":tableView]))
    

    required init?(coder aDecoder: NSCoder) 
        fatalError("init is not done")
    
    
    func setUpViews() 
        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(MyCell.self, forCellReuseIdentifier: cellId) 
    


extension FirstCollectionViewCell: UITableViewDataSource, UITableViewDelegate 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return 5
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MyCell
        cell.label.text = "Testing testing"
        return cell
    
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return 40.0
    


class MyCell:UITableViewCell 
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) 
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setUpViews()
    
    
    required init?(coder aDecoder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    
    
    // creating a label to display some dummy text
    let label:UILabel = 
        let label = UILabel()
        label.text = "test"
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    ()
    
    func setUpViews() 
        addSubview(label)
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":label]))
        addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":label]))
    

【讨论】:

如果tableview单元格有动态高度怎么办

以上是关于以编程方式在特定 UICollectionViewCell 内的 TableView?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式将 UICollectionView 嵌套在 UIVIew 中

以编程方式创建 UICollectionView

你能以编程方式修改 UICollectionView 滚动方向吗?

以编程方式添加 UICollectionView 时应用程序崩溃

在 Swift 中以编程方式在 UITableViewCell 中创建一个 UICollectionView

以编程方式将 UIButtons 添加到 UICollectionView 单元格的 uiimage