【发布时间】:2022-01-30 19:20:56
【问题描述】:
如何在 UICollectionView 单元中插入 UIViewController?
【问题讨论】:
如何在 UICollectionView 单元中插入 UIViewController?
【问题讨论】:
您需要制作一个自定义容器视图控制器: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)
}
对于容器中的每个单元格,您必须在单元格的内容视图上使用正确的子视图控制器调用上述函数。
注意不要尝试将多个视图控制器添加到同一个单元格上,并确保它们也被正确删除。
这个想法很复杂,不利于简单的堆栈溢出答案,但希望以上内容足以让您入门。
【讨论】:
问题 1,对于表格视图,如果您只有少量单元格,您只需单击以使单元格变为静态 - 就完成了。不幸的是,对于集合视图,Apple 没有添加使它们成为静态的能力。所以你必须努力去做。
本教程:https://stackoverflow.com/a/23403979/294884
完美地解释了如何动态添加容器视图(到普通场景中)。
向下滚动到“动态加载...”
事实上,你的单元必须知道它自己的老板视图控制器:
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
}
完全按照上面的教程进行操作,但是:在添加子 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()
}
}
呼。
【讨论】:
Daniel 说的是对的,但是如果您必须在UICollectionViewCell 或UITableViewCell 中添加多个childViewControllers,则维护起来可能很麻烦。
这是来自 Sroush Khanlou 的一篇不错的帖子,它处理了这种复杂性并简化了流程。
【讨论】:
通用方法
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) {
...
}
}
【讨论】: