UICollectionView shouldShowMenuForItemAt Not Calle

2019-08-31 02:05发布

问题:

I have a stock standard UICollectionView in a UIViewController that is its delegate. However the shouldShowMenuForItemAt func is not called for a long press. I have added a didSelectItemAt func which does get called on clicking a cell to make sure the delegate is indeed wired up correctly.

I also implemented the canPerformAction to return true and performAction in the delegate along with the canPerformAction and canBecomeFirstResponder to return true in my UICollectionViewCell subclass. None of these func's get called for a long press of a cell. Any suggestions?

回答1:

The missing piece of the puzzle, which most people seem to miss, is that in order for menus to work (in a collection view or table view), the cell must implement the selector.

Here's a minimal example. Instruction: Make a new project using the Single View App template. Copy this code and paste it into ViewController.swift, so as to replace completely everything in that file. Run. Long press on a green square. Enjoy. (The menu item does nothing; the point is, you will see the menu item appear.)

import UIKit
class Cell : UICollectionViewCell {
    @objc func f(_ : Any) {}
}
class ViewController: UIViewController {
    let cellid = "cellid"
    @nonobjc private let howdy = #selector(Cell.f)
    override func viewDidLoad() {
        super.viewDidLoad()
        let cv = UICollectionView(frame: self.view.bounds, collectionViewLayout: UICollectionViewFlowLayout())
        self.view.addSubview(cv)
        cv.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        cv.delegate = self
        cv.dataSource = self
        cv.register(Cell.self, forCellWithReuseIdentifier: cellid)
    }
}
extension ViewController : UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 100
    }
    func collectionView(_ cv: UICollectionView, cellForItemAt ip: IndexPath) -> UICollectionViewCell {
        let cell = cv.dequeueReusableCell(withReuseIdentifier: cellid, for: ip)
        cell.backgroundColor = .green
        return cell
    }
    func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
        let mi = UIMenuItem(title:"Howdy", action:howdy)
        UIMenuController.shared.menuItems = [mi]
        return true
    }

    func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
        return (action == howdy)
    }
    func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
    }
}