访问UICollectionView的父UIViewController

10
我的问题很简单。我有一个包含UICollectionView的UIViewController。在初始化单元格时,我为每个单元格添加了一个手势识别器,这样当您点击并按住它时,它将调用具有选择器的功能。
然后,该功能创建一个UIAlertController,我想要呈现它。(基本上,您按住一个单元格,它会问您是否要删除它,如果您说是,它就会从CollectionView中消除它)
问题是,我无法从我的UICollectionView中显示UIAlertController,因为它不是ViewController。
我希望从包含UICollectionView的UIViewController中以编程方式获取它,以便从UICollectionView实现中的函数呈现此警报。

你能否贴一段代码?只需要包含创建类和创建 UIAlert 的代码部分。 - Eric
1
UICollectionView 子类化以持有一个 weak delegate: UIViewController? 字段,并在视图控制器中使用 collectionView.delegate = self。然后您可以使用委托进行演示。 - sdasdadas
如果您仍在寻找解决方案,我有一个答案可以让您获取任何视图的第一个父视图控制器,因此我可以发布它。 - Rhm Akbari
1个回答

14

我通过在我的自定义UICollectionViewCell中创建一个协议,并将这些事件委托回UIViewController来实现这一点,就像这样:

在你的MyCollectionViewCell

protocol MyCollectionViewCellDelegate: AnyObject {
    func didLongPressCell()
}

class MyCollectionViewCell: UICollectionViewCell {

    weak var delegate: MyCollectionViewCellDelegate?

    func longPressAction() {
        if let del = self.delegate {
            del.didLongPressCell
        }
    }

}

然后回到你的 MyViewController

class MyViewController: UIViewController, MyCollectionViewCellDelegate {

    func collectionView(
        collectionView: UICollectionView, 
        cellForItemAtIndexPath indexPath: NSIndexPath
    ) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! MyCollectionViewCell
        cell.delegate = self
        return cell
    }

    func didLongPressCell() {
        // do what you want with the event from the cell here
    }

}

需要记住的重要部分是:

  • 为每个单元格设置委托 cell.delegate = self

  • 将委托引用设置为弱引用,以避免潜在的保留循环 weak var delegate: MyCollectionViewCellDelegate?

  • 在您想要接收事件的视图控制器中采用新协议 class MyViewController:UIViewController, MyCollectionViewCellDelegate


编辑:如果你已经创建了UICollectionView的子类,那么请传递一个指向视图控制器的引用,这样你就可以像下面这样使用它。

现在你的MyViewController将会是这个样子

class MyViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let collectionView = MyCollectionView()
        collectionView.viewController = self
        self.view.addSubview(collectionView)
    }

}

还有你自定义的集合视图MyCollectionView

class MyCollectionView: UICollectionView, MyCollectionViewCellDelegate {

    weak var viewController: UIViewController?

    func collectionView(
        collectionView: UICollectionView, 
        cellForItemAtIndexPath indexPath: NSIndexPath
    ) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! MyCollectionViewCell
        cell.delegate = self
        return cell
    }

    func didLongPressCell() {
        if let vc = self.viewController {
            // make use of the reference to the view controller here
        }
    }

}

UICollectionViewCell 与之前相同


1
我会将代理对象声明为weak以避免引用循环。 - nils
1
@nils 我已经更新了答案 - 只是进行了一次快速搜索,我的当前项目有39个可能需要更新的委托 :| - Wez
谢谢!这看起来不错,但问题是 cellForItemAtIndexPath 函数被调用在 UICollectionView 中而不是 UIViewController 中。我不是很理解协议,从 UICollectionView 到 UIViewController 是否有一种方法可以像上面你所做的那样实现? - Pelayo Martinez
@PelayoMartinez 你把答案标记为已接受,这是否意味着你解决了问题?还是说你仍然需要帮助?如果需要帮助,我会在聊天室里等着。 - Wez
@Wez 谢谢!协议正是解决这个问题的正确方式。 - Pelayo Martinez
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接