collectionView didSlectRow bug

2019-09-25 06:41发布

Hello on a specific viewController of my project i have a UICollectionView with a custom class cell. But i have a big problem this that func :

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("tapped on a cell")
    }

when is click on a cell and instant realease (normal click) it does nothing, just nothing.

if i press and hold about 1s without release the finger it become grey, highlighted

And if i press and hold at least 3 seconds release the finger didSelectItemAt is executed correctly. I tried to do the same on another project and that's work great but not on this VC and i really don't find the problem. The VC Bugged is of addTest clas in Main.storyboard

2条回答
Deceive 欺骗
2楼-- · 2019-09-25 07:12

The insight of Mojtaba Hosseini is very clever, but the answer given might not be quite correct.

It turns out that there is a UITapGestureRecognizer on the main view; if it recognizes before the tap on the cell, it prevents cell selection. But if you merely set cancelsTouchesInView to false on that gesture recognizer, then they both operate, and that seems unlikely to be what is wanted. We surely want the cell tap and not the tap gesture recognizer tap.

The correct solution is thus to give the tap gesture recognizer a delegate and implement gestureRecognizerShouldBegin. Here, we look to see where the tap is. If it is within the bounds of a cell, we return false; otherwise we return true. We thus mediate between the cell tap and gesture recognizer tap.

Here is a possible implementation, demonstrated in a highly simplified form:

extension UIView {
    func isDescendant(of whattype:UIView.Type) -> Bool {
        var sup : UIView? = self.superview
        while sup != nil {
            if (whattype == type(of:sup!)) {
                return true
            }
            sup = sup!.superview
        }
        return false
    }
}

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UIGestureRecognizerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        let t = UITapGestureRecognizer(target: self, action: #selector(tap))
        self.view.addGestureRecognizer(t)
        t.delegate = self
    }

    @objc func tap(_:UIGestureRecognizer) {
        print("tap")
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("select")
    }

    func gestureRecognizerShouldBegin(_ gr: UIGestureRecognizer) -> Bool {
        if let v = gr.view {
            let loc = gr.location(in: v)
            if let v2 = v.hitTest(loc, with: nil) {
                return !v2.isDescendant(of: UICollectionViewCell.self)
            }
        }
        return true
    }
}

As you can see, we look to see whether the tap is inside a collection view cell; if it is, our gesture recognizer is prevented from recognizing, and the selection succeeds immediately.

查看更多
我只想做你的唯一
3楼-- · 2019-09-25 07:15

Probably there is a UIGesture or another interactable thing underneath the collection view. You should DISABLE its ability to cancel touches in view in interface builder:

Attributes inspector

or in code:

myTapGestureRecognizer.cancelsTouchesInView = false
查看更多
登录 后发表回答