9

I have a UIViewController containing a MKMapView (in fact, it contains a full screen container containing the MKMapView, but it shouldn't have any impact)

I implemented a UIScreenEdgePanGestureRecognizer (to show a drawer) like this:

self.swipeRight = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleEdgeGesture:)];
[self.swipeRight setEdges:UIRectEdgeLeft];
[self.swipeRight setDelegate:self];
[self.view addGestureRecognizer:self.swipeRight];

and to make it works I had to add the following method (returning YES):

(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;

But then the map is moving at the same time as the drawer is appearing! I've tried all kind of tricks to prevent it but was not able to... (I tried shouldBeRequiredToFailByGestureRecognizeror requireGestureRecognizerToFail for example)

Any idea how I could prevent the MapView from moving when the gesture is a ScreenEdgePan from LeftEdge?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Sebastien C.
  • 2,099
  • 17
  • 21

5 Answers5

16

What I did in my app was the following:

UIScreenEdgePanGestureRecognizer *popRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePopRecognizer:)];
popRecognizer.edges = UIRectEdgeLeft;
popRecognizer.delegate = self;

Then set the delegate to YES as you said

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

And enable/disable scrolling of the mapview like this

- (void)handlePopRecognizer:(UIScreenEdgePanGestureRecognizer*)recognizer
{
    if(recognizer.state == UIGestureRecognizerStateBegan){
        _mapView.scrollEnabled = NO;
    } else if(recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled){
        _mapView.scrollEnabled = YES;

    }
}

Hope it helps.

Cedrick
  • 566
  • 3
  • 13
  • Hi thanks, I didn't had this idea, I'm going to try... The only issue is that I don't have access to the mapView as it's in a container view, so I'll have to use a notification. I'll try and tell you! – Sebastien C. Jul 22 '14 at 17:00
3

The pan gesture on the map needs to be cancelled as soon as the UIScreenEdgePanGestureRecognizer begins to recognize. To achieve this it is sufficient to set scrollEnabled to NO momentarily. This will cancel the other gesture recognizer.

- (void) handleEdgeGesture:(UIScreenEdgePanGestureRecognizer*)recognizer
{
    if(recognizer.state == UIGestureRecognizerStateBegan) {
        // cancel simultaneous gesture on map view
        _mapView.scrollEnabled = NO;
        _mapView.scrollEnabled = YES;
    }
}
Felix
  • 35,354
  • 13
  • 96
  • 143
  • Thanks @phix23, as I said to Cedrick it's a really cool idea, I'll test it asap, even if I don't have direct access to the mapView – Sebastien C. Jul 22 '14 at 17:02
  • Why can't you just expose the mapview from the container? – Cedrick Jul 23 '14 at 11:15
  • The container let the user switch between a map view and a listview, so I have a container with 2 custom segues forwarding to 2 controllerView (I can't have 2 embed segue): so I can't directly expose the mapview to the container (I only have access to the mapview in the performSegue method). I just have to finish my actual git branch to test your solutions! – Sebastien C. Jul 25 '14 at 14:26
  • Thanks to both of you, it works! As Cedrick answered first I'm going to give him the bounty – Sebastien C. Jul 26 '14 at 09:12
  • This worked perfectly! thanks so much. I added a check to see if scrolling was enabled first before temporarily disabling it & enabling again. that way if it was already disabled, you won't risk enabling scrolling when you didn't intend to. – Natalia Dec 14 '16 at 00:19
2

The following combination worked for me without touching the map view.

// This is to ensure UIScreenEdgePanGestureRecognizer won't be blocked by other gestures. 
// You may need to do some logic checking before returning YES.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
  return YES;
}
// This is to prevent other recognisers when UIScreenEdgePanGestureRecognizer
// is recognising the gesture. Again, you may want to do some logic checking
// before returning to YES.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{

  return YES;
}
Mingming
  • 2,189
  • 20
  • 21
1
- (void) handleEdgeGesture:(UIScreenEdgePanGestureRecognizer*)recognizer : (id)sender
{
    if(recognizer.state == UIGestureRecognizerStateBegan && sender == GMSMapView) {
        // cancel simultaneous gesture on map view
        _mapView.isUserInteractionEnabled = NO;
    }
}
  • 2
    It's pretty much the same solution, btw 'isUserInteractionEnabled' can't be set, thats the getter. You should use 'userInteractionEnabled'. – Cedrick Jul 25 '14 at 09:59
1

I believe that the quickest solution is to make a thin view (with transparent background color) on top of mapView, where your gesture should not work on mapView. i.e. enter image description here

arturdev
  • 10,884
  • 2
  • 39
  • 67
  • 1
    Hello @arturdev! Well, that's what I did before asking here :) and I didn't like it at all... because I do need to have a sufficient width to make it works and then it's annoying because sometime I just want to drag the map and it opens the drawer... It feels more like a hack – Sebastien C. Jul 28 '14 at 13:43