在UICollectionViewCell中添加UICollectionView

chr*_*702 4 ios uicollectionview swift

我正在使用Swift为我工作的医院构建一个iOS应用程序.

不知何故,在一个特定的功能,我必须把一个UICollectionView内部UICollectionViewCell.我想要实现的是父母的每个内容UICollectionView(垂直滚动)将有几个孩子(可以水平滚动),具体取决于父行.

为了说明,我必须显示医生名单(姓名和照片),然后我必须在他们的名字和照片下面显示他们的每个练习时间表.实践时间表因每位医生而异.所以,我必须把它放在里面UICollectionView.

我尝试过在网上找到的几种解决方案,但我仍然无法接近它.

我无法解决的最大问题是:我不知道代码中加载子数据源(医生日程安排)的位置以及何时可以加载它,因为我不能有两个函数,如下所示:

collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
Run Code Online (Sandbox Code Playgroud)

这是我想要实现的目标

集合视图的设计

UIImage和医生的名字(UILabel)是在父UICollectionViewCell(垂直滚动),然后在框中(实习n天的练习时间),一切都是孩子UICollectionView(水平滚动)

PS:有很多医生,每个医生都有几天练习.

请帮我怎么做

Bik*_*ram 7

如果你真的想在collectionViewCell中插入一个collectionView,那么有一个非常简单的步骤.创建UICollectionView的实例并将其添加到collectionViewCell.如果您愿意,可以使用此示例.

//
//  ViewController.swift
//  StackOverFlowAnswer
//
//  Created by BIKRAM BHANDARI on 18/6/17.
//  Copyright © 2017 BIKRAM BHANDARI. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    let cellId = "CellId"; //Unique cell id

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red; //just to test

        collectionView.register(Cell.self, forCellWithReuseIdentifier: cellId) //register collection view cell class
        setupViews(); //setup all views
    }

    func setupViews() {

        view.addSubview(collectionView); // add collection view to view controller
        collectionView.delegate = self; // set delegate
        collectionView.dataSource = self; //set data source

        collectionView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true; //set the location of collection view
        collectionView.rightAnchor.constraint(equalTo:  view.rightAnchor).isActive = true; // top anchor of collection view
        collectionView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true; // height
        collectionView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true; // width

    }

    let collectionView: UICollectionView = { // collection view to be added to view controller
        let cv = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()); //zero size with flow layout
        cv.translatesAutoresizingMaskIntoConstraints = false; //set it to false so that we can suppy constraints
        cv.backgroundColor = .yellow; // test
        return cv;
    }();

    //deque cell
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath);
//        cell.backgroundColor = .blue;
        return cell;
    }

    // number of rows
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5;
    }

    //size of each CollecionViewCell
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: view.frame.width, height: 200);
    }
}

// first UICollectionViewCell
class Cell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    let cellId = "CellId"; // same as above unique id

    override init(frame: CGRect) {
        super.init(frame: frame);

        setupViews();
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId); //register custom UICollectionViewCell class.
        // Here I am not using any custom class

    }


    func setupViews(){
        addSubview(collectionView);

        collectionView.delegate = self;
        collectionView.dataSource = self;

        collectionView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true;
        collectionView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true;
        collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true;
        collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true;
    }

    let collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout();
        layout.scrollDirection = .horizontal; //set scroll direction to horizontal
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout);
        cv.backgroundColor = .blue; //testing
        cv.translatesAutoresizingMaskIntoConstraints = false;
        return cv;
    }();

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath);
        cell.backgroundColor = .red;
        return cell;
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5;
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: self.frame.width, height: self.frame.height - 10);
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
Run Code Online (Sandbox Code Playgroud)

截图示例


Jos*_*ent 5

这可能有点晚了,但对于仍在尝试寻找答案的人们来说。

经过一些研究和挖掘,我偶然发现了几篇文章,说明了为什么你不应该让你的单元格成为你的 collectionView 的委托。所以,我迷失了,因为我发现的几乎所有解决方案都在这样做,直到我最终找到了我认为是嵌套 CollectionView 的最佳方法。

为了提供一些背景知识,我的应用程序在另一个 collectionView 的不同单元格内不仅包含一个而是 2 个 collectionView,因此使用标签设置委托等等,并不是真正的最佳方法,也不是正确的 OO 解决方案。

因此,最好的方法如下:

首先,您必须创建一个不同的类来充当内部 collectionView 的委托。我是这样做的:

class InnerCollectionViewDelegate: NSObject, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
 // CollectionView and layout delegate methods here
 // sizeForItemAt, cellForItemAt, etc...
}
Run Code Online (Sandbox Code Playgroud)

现在,在您的内部collectionView(或者更确切地说,您拥有内部collectionView的单元格)中创建一个函数,该函数将允许您设置其委托

class InnerCell: UICollectionViewCell {

    var collectionView: UICollectionView

    init() {
        let layout = UICollectionViewFlowLayout()
        collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: frame.width, height: frame.height), collectionViewLayout: layout)
     }

    func setCollectionViewDataSourceDelegate(dataSourceDelegate: UICollectionViewDataSource & UICollectionViewDelegate) {
            collectionView.delegate = dataSourceDelegate
            collectionView.dataSource = dataSourceDelegate
            collectionView.reloadData()
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,在您拥有最外层(主)collectionView 的 ViewController 中执行以下操作:

首先实例化内部collectionView的委托

var innerDelegate = InnerCollectionViewDelegate()
Run Code Online (Sandbox Code Playgroud)

进而

override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        if let cell = cell as? InnerCell {
            cell.setCollectionViewDataSourceDelegate(dataSourceDelegate: innerDelegate)
        }
}
Run Code Online (Sandbox Code Playgroud)

这可能并不完美,但至少您可以实现关注点分离,因为您的单元不应该成为代表。请记住,您的单元格应该只负责显示信息,而不是试图弄清楚 collectionView 的大小应该是多少,等等。

我确实找到了处理设置 collectionViews 标签等的类似答案,但我发现这使得单独处理每个 collectionView 变得更加困难,而且处理标签不会导致意大利面条代码或意外行为。

我省略了单元格的注册和出队,但我相信你们都熟悉这一点。如果没有,请告诉我,我会尽力引导您完成它。