Tap on a UIButton in a UITableViewCell overlaid by UIScrollView doesn't trigger button's target

I have a UITableView with UITableViewCell like this:

I added a UITapGestureRecognizer (let's call the target targetCell) on the tableView to manage when the user tap on a cell. On the Button, let's call the target targetButton.

On top of the cell, I added a UIScrollView as an overlay.

What I would like to do it that when there is a pan/swipe anywhere on the cell/scrollView, then the pan is detected.

But if there is a tap on the button then targerButton is triggered, if it's outside targetCell is triggered.

So far, only targetCell is triggered, inside or outside of the button area. If I remove the UIScrollView, it works fine.

So at first I thought about overriding func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool. The problem is that at this stage, it doesn't make the difference between a tap and a pan so it doesn't solve my problem.

Then I thought about overriding func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) like the following:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let location = touches.first?.locationInView(tableView) {

        var buttonFrame = CGRectMake(frame.width - 50, 0, 50, bounds.height)
        buttonFrame.origin.y = (convertRect(buttonFrame, toView: tableView).minY)

        let toNextResponder = buttonFrame.contains(location)

        if toNextResponder {
            self.nextResponder()?.touchesBegan(touches, withEvent: event)
        } else {
            super.touchesBegan(touches, withEvent: event)
        }
    } else {
        super.touchesBegan(touches, withEvent: event)
    }
}

It didn't work. Then I realised that self.nextResponder()? was the UITableViewCellContentView so I thought maybe, call touchesBegan(touches, withEvent: event)directly on the button. So I changed touchesBegan to this:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let location = touches.first?.locationInView(tableView) {

        var buttonFrame = CGRectMake(frame.width - 50, 0, 50, bounds.height)
        buttonFrame.origin.y = (convertRect(buttonFrame, toView: tableView).minY)

        let toNextResponder = buttonFrame.contains(location)

        if toNextResponder {
            if let cellContentView = self.nextResponder() as? UIView {
                let button = findButtonInView(cellContentView)
                button?.touchesBegan(touches, withEvent: event)
            }
        } else {
            super.touchesBegan(touches, withEvent: event)
        }
    } else {
        super.touchesBegan(touches, withEvent: event)
    }
}

private func findButtonInView(view: UIView) -> UIButton? {
    if view is UIButton {
        return view as? UIButton
    } else {
        var button: UIButton?
        for subview in view.subviews {
            button = findButtonInView(subview)
            if let _ = button {
                return button
            }
        }

        return button
    }
}

And... it doesn't work, targetCell only gets triggered whether you tap on the button or not. I noticed something though it that when I call chartButton?.touchInside I get false.

What did I do wrong? Or what should I have done?

Answers


Well I found a solution but I don't really like it as it feels more like a hack than a proper one.

I basically execute the button's target when a tap gesture is recognized within the button's area:

override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
    if gestureRecognizer is UITapGestureRecognizer {
        let location = (gestureRecognizer as! UITapGestureRecognizer).locationInView(tableView)
        var buttonFrame = CGRectMake(frame.width - 50, 0, 50, bounds.height)
        buttonFrame.origin.y = (convertRect(buttonFrame, toView: tableView).minY)

        if buttonFrame.contains(location) {
            button.sendActionsForControlEvents(.TouchUpInside)
            return false
        }
    }

    return super.gestureRecognizerShouldBegin(gestureRecognizer)
}

If anyone has a better way or think my way is wrong please let me know.


Need Your Help

Test assembly code on a mac

macos assembly emulation bootloader

A while back I was following some tutorials an assembly. I was running it all on a windows machine, compiling with NASM and then writing the compiled code to a floppy disk, then reboot and try the ...

How to Detect Mousedown + Mousemove Left or Right Direction

javascript jquery

Can you please take a look at this demo and let me know how I can detect whether the mousemove is toward Left or Right?