1

I'm trying to pop up a popover for my app. So far, the popover pops up at a fixed coordinate, I'm trying to get it to pop at the point where the user tapped. This is what I have:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    print("touchesbegan")
    for touch in touches{
        //Handle touch
        let location = touch.locationInView(self.view)
        let storyboard = UIStoryboard(name: "Main", bundle: nil)

        let vc = storyboard.instantiateViewControllerWithIdentifier("ColonyPopoverController") as! ColonyPopoverController
        vc.modalPresentationStyle = .Popover
        vc.preferredContentSize = CGSizeMake(200, 150)

        if let popoverController = vc.popoverPresentationController {
            popoverController.delegate = self
            popoverController.sourceRect = CGRectMake(location.x, location.y, 20, 10)
            popoverController.sourceView = self.view
            self.presentViewController(vc, animated: true, completion: nil)
        }
    }
}

I notice that the print statement never prints when I tap on the simulator.

I have interaction and multi-touch enabled in my view. I know that that works fine because I also have it integrated with Google Maps, so that when I tap, a google pin appears:

func mapView(mapView: GMSMapView!, didTapAtCoordinate coordinate: CLLocationCoordinate2D) {
    print("You tapped at \(coordinate.latitude), \(coordinate.longitude)")
    let marker = GMSMarker()
    marker.position = CLLocationCoordinate2DMake(coordinate.latitude, coordinate.longitude)
    marker.title = "Sydney"
    marker.snippet = "Australia"
    marker.map = mapView

}

and I see the print statements printing as well. Not sure what I'm missing here.

User interaction is enabled for both the superview and the view:

enter image description here

enter image description here

Peter Todd
  • 8,561
  • 3
  • 32
  • 38
Siddhartha
  • 4,296
  • 6
  • 44
  • 65

3 Answers3

8

There are three main reasons why a view doesn't receive touches when you expect it to:

  • It has userInteractionEnabled set to false. Apparently you've already verified that this isn't the case.

  • Some other view is “on top of” the view of interest, and is receiving the touches. Note that a child view is on top of its parent (in the area covered by the child), and a view lower in the storyboard document outline is on top of any siblings that are higher in the outline. (In your screen shot, KittyMapper® is on top of Map View, in any area where they overlap.) You need to set userInteractionEnabled to false if you don't want the top view to receives touches.

  • The view of interest is outside the bounds of its parent.

    Hit testing works recursively: the window calls hitTest(_:withEvent:) on each of its children (in top-to-bottom order) until one returns non-nil; hitTest(_:withEvent:) returns nil immediately if pointInside(_:withEvent:) returns false; otherwise hitTest(_:withEvent:) calls hitTest(_:withEvent:) on child (in top-to-bottom order) until one returns non-nil, and returns self if none of the children report a hit.

    Thus if a child is outside its parent's bounds, it can be visible (if all ancestors have clipsToBounds set to false), but never receive touches, because its parent's pointInside(_:withEvent:) will reject touches that appear to be on the child view.

You may be able to diagnose the last two cases by inspecting your view hierarchy using Xcode's “Debug View Hierarchy” feature.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Thanks for your answer. I used gestureRecognizer instead and notice the same behavior. I believe my map is overriding the touch recognizers with its ```didTapAtCoordinate``` method. I wonder if the 2 are not usable in conjunction. Going to try out the ```Debug View Hierarchy``` feature, thanks. – Siddhartha Dec 30 '15 at 19:31
  • I found the reason. Googlemaps' GMSView consumes other gestures in view and it has to be disallowed: ```mapView.settings.consumesGesturesInView = false;```. – Siddhartha Dec 31 '15 at 04:09
1

Turns out Googlemaps' GMSView consumes other gestures in view and it has to be explicitly disallowed:

mapView.settings.consumesGesturesInView = false;
Siddhartha
  • 4,296
  • 6
  • 44
  • 65
0

If userInteractionEnabled is true then touchesBegan should be called and your code will work and popup will appear where the user taps.

If your view is a subview then make sure userInteractionEnabled is true on any superviews. Have a look at this answer for more info on touchesBegan not being called.

Community
  • 1
  • 1
Peter Todd
  • 8,561
  • 3
  • 32
  • 38
  • Thanks for your answer. User interaction is enabled for both the superview and the view, attached screenshots and updated question. – Siddhartha Dec 30 '15 at 17:33
  • 1
    I found the reason. Googlemaps' GMSView consumes other gestures in view and it has to be disallowed: ```mapView.settings.consumesGesturesInView = false;```. – Siddhartha Dec 31 '15 at 04:09