在UICollectionView单元格中添加UIViewController

Tyl*_*utt 8 ios swift

我试图在UICollectionView Cell中添加一个UIViewController,但不知道该怎么做.

Dan*_* T. 9

您需要创建一个自定义容器视图控制器:https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html

func display(contentController content: UIViewController, on view: UIView) {
    self.addChildViewController(content)
    content.view.frame = view.bounds
    view.addSubview(content.view)
    content.didMove(toParentViewController: self)
}
Run Code Online (Sandbox Code Playgroud)

对于容器中的每个单元格,您必须在单元格的内容视图上使用正确的子视图控制器调用类似上述函数的内容.

小心不要尝试将多个视图控制器添加到同一个单元格中,并确保它们也被正确删除.

这个想法很复杂,不利于简单的堆栈溢出答案,但希望上面的内容足以让你开始.


Fat*_*tie 6

现在这样做相对容易

问题 1,对于表格视图,如果您只有少量单元格,您只需单击即可使单元格静态 - 就完成了。不幸的是与收集的意见,苹果并没有增加,使其静态的能力。所以你必须以艰难的方式去做。

1、弄清楚如何在普通场景中动态添加容器视图:

本教程:https : //stackoverflow.com/a/23403979/294884

完美解释了如何动态添加容器视图(到普通场景)。

向下滚动到“动态加载...”

在此处输入图片说明

2、但是单元格不是视图控制器!

事实是你的单元必须知道它自己的老板视图控制器:

class CrazyBigCell: UICollectionViewCell {
    weak var boss: ThatClass? = nil
Run Code Online (Sandbox Code Playgroud)

当你制作单元格时,设置那个“老板”变量......

func collectionView(_ collectionView: UICollectionView,
                cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
    let cell = collectionView.dequeueReusableCell(
      withReuseIdentifier: "CrazyBigCellID", for: indexPath) as! CrazyBigCell
    
    cell.boss = self
    cell.data = someData[indexPath.row]
    
    return cell
}
Run Code Online (Sandbox Code Playgroud)

3、所以安装了container view,但是用的是boss的VC

完全按照上面的教程进行,但是:在添加子 VC 时,将其添加到老板VC。

class CrazyBigCell: UICollectionViewCell {
    weak var boss: ThatClass? = nil
    @IBOutlet var chatHolder: UIView!
    var chat: Chat? = nil
    ....
Run Code Online (Sandbox Code Playgroud)

所以......秘诀是:通常你会说类似的话

        self.addChild(chat!)
Run Code Online (Sandbox Code Playgroud)

但它是

        boss?.addChild(chat!)
Run Code Online (Sandbox Code Playgroud)

所以 ...

private func _installChatBlock() {
    if chat == nil {
        print(">>> installing chat for " + name etc)
        
        chat = _sb("Chat") as? Chat
        boss?.addChild(chat!)
        chatHolder.addSubview(chat!.view)
        chat!.view.bindEdgesToSuperview()
        chat!.didMove(toParent: boss)
    }
    else {
        print(">>> already had a Chat for " + name etc)
    }
    
    chat!.data = data  // or whatever
    chat!.loadOurChat() // or whatever
}
Run Code Online (Sandbox Code Playgroud)

在哪里打电话_installChatBlock

很可能,在您为此单元格设置数据的地方调用

var data: [String : Any] = [:] { // whatever
    didSet {
        headline.text = data["headline.text"] // etc
        name.text = data["name"] // etc
        _installChatBlock()
    }
}
Run Code Online (Sandbox Code Playgroud)

呼。


Ram*_*sad 5

Daniel 说的是正确的,但是如果您必须childViewControllers向 a UICollectionViewCellor 中添加许多UITableViewCell,则维护起来可能很麻烦。

这是 Suroush Khanlou 的一篇很好的帖子,它处理了这种复杂性并简化了过程。

http://khanlou.com/2015/04/view-controllers-in-cells/


And*_*uev 5

通用方法

protocol ChildControllersManagerDelegate: class {
    associatedtype ViewControllerType: UIViewController
    func willAdd(_ childViewController: ViewControllerType, at index: Int)
}

final class ChildControllersManager<V, D: ChildControllersManagerDelegate> where D.ViewControllerType == V {
    private var viewControllers = [Int: V]()
    weak var delegate: D?

    func addChild(at index: Int, to viewController: UIViewController, displayIn contentView: UIView) {
        let childVC: V
        if let vc = viewControllers[index] {
            print("Using cached view controller")
            childVC = vc
        } else {
            print("Creating new view controller")
            childVC = V()
            viewControllers[index] = childVC
        }

        delegate?.willAdd(childVC, at: index)

        viewController.addChild(childVC)
        childVC.view.frame = contentView.bounds
        contentView.addSubview(childVC.view)
        childVC.didMove(toParent: viewController)
    }

    func remove(at index: Int) {
        print("Remove at \(index)")
        guard let vc = viewControllers[index] else { return }
        vc.willMove(toParent: nil)
        vc.view.removeFromSuperview()
        vc.removeFromParent()
    }

    func cleanCachedViewControllers(index: Int) {
        let indexesToClean = viewControllers.keys.filter { key in
            key > index + 1 || key < index - 1
        }
        indexesToClean.forEach {
            viewControllers[$0] = nil
        }
    }
}

...

extension ViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        childControllersManager.addChild(at: indexPath.row, to: self, displayIn: cell.contentView)
    }

    func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        childControllersManager.remove(at: indexPath.row)
        childControllersManager.cleanCachedViewControllers(index: indexPath.row)
    }
}

extension ViewController: ChildControllersManagerDelegate {
    typealias ViewControllerType = MyVC

    func willAdd(_ childViewController: MyVC, at index: Int) {
         ...
    }
}
Run Code Online (Sandbox Code Playgroud)