【问题标题】:Adding a UIViewController inside a UICollectionView Cell在 UICollectionView 单元中添加 UIViewController
【发布时间】:2022-01-30 19:20:56
【问题描述】:

如何在 UICollectionView 单元中插入 UIViewController?

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    您需要制作一个自定义容器视图控制器: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)
    }
    

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

    注意不要尝试将多个视图控制器添加到同一个单元格上,并确保它们也被正确删除。

    这个想法很复杂,不利于简单的堆栈溢出答案,但希望以上内容足以让您入门。

    【讨论】:

    • @TylerRutt 你有一个示例代码来说明你是如何让它工作的吗?我还是想不通..
    • 完美...谢谢队友(y)
    【解决方案2】:

    现在比较容易做到这一点

    问题 1,对于表格视图,如果您只有少量单元格,您只需单击以使单元格变为静态 - 就完成了。不幸的是,对于集合视图,Apple 没有添加使它们成为静态的能力。所以你必须努力去做。

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

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

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

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

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

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

    class CrazyBigCell: UICollectionViewCell {
        weak var boss: ThatClass? = nil
    

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

    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
    }
    

    3、所以安装容器视图,但是用的是老大的VC

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

    class CrazyBigCell: UICollectionViewCell {
        weak var boss: ThatClass? = nil
        @IBOutlet var chatHolder: UIView!
        var chat: Chat? = nil
        ....
    

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

            self.addChild(chat!)
    

    其实是

            boss?.addChild(chat!)
    

    所以...

    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
    }
    

    在哪里打电话给_installChatBlock

    很可能,调用你为这个单元格设置数据的地方

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

    呼。

    【讨论】:

      【解决方案3】:

      Daniel 说的是对的,但是如果您必须在UICollectionViewCellUITableViewCell 中添加多个childViewControllers,则维护起来可能很麻烦。

      这是来自 Sroush Khanlou 的一篇不错的帖子,它处理了这种复杂性并简化了流程。

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

      【讨论】:

        【解决方案4】:

        通用方法

        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) {
                 ...
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-11-06
          • 1970-01-01
          • 1970-01-01
          • 2014-07-11
          • 2016-07-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多