Drag/pan gestures on a GMSMapView not getting captured after update to SDK 1.3.1
Asked Answered
T

6

5

I'm having a strange problem with capturing drag/pan gestures on a GMSMapView through a Gesture Recognizer. This problem surfaced only after updating from GMS 1.2 to 1.3.1, where (quoting the documentation),

Touches are consumed more agressively by GMSMapView

I have a UIViewController holding a GMSMapView under its main view. I found GMSMapDelegate does not provide methods for handling drag/pan gestures, so I added a UIPanGestureRecognizer to the UIViewController, linked it to an IBAction selector, and set referencing outlet and outlet collection, as per the screenshot linked here: https://i.sstatic.net/gktoa.png

So any drag action would simply trigger the recognizeDragOnMap: selector, as below:

-(IBAction)recognizeDragOnMap:(id)sender {
    NSLog(@"recognizeDragOnMap");

    UIGestureRecognizer *gestureRecognizer = (UIGestureRecognizer *)sender;
    if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
        NSLog(@"Still dragging");
        return;
    }
    NSLog(@"DragEnded");

    GMSCameraPosition *position;

    if ((position = self.mapView.camera)) {
        self.automaticCameraPositionChange = NO;
        CLLocationCoordinate2D coordinate = [position targetAsCoordinate];
        CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
        [self.origin dragPinToLocation:location];
    } else {
        NSLog(@"No map camera");
    }
}

This setup used to work perfectly under GMS 1.2.0. After the update, the GMSMapView responds to the gestures like it used to, however the method above never gets called!

Anyone have an idea what's up and/or how to fix it?

Tambourine answered 2/7, 2013 at 0:43 Comment(2)
Being very paranoid, I did the following tests: 1) set up an equivalent UIPanGestureRecognizer on another UIViewController without the GMSMapView... and lo and behold, works without a hitch. 2) reverted my project to a pre-1.3.1 commit, also works without a hitch.Tambourine
Also -- I know about mapView: didChangeCameraPosition:, but that's not sufficient: I need to be able to distinguish between camera updates generated by gestures on the map and those generated by other operations.Tambourine
T
12

For version 1.4 or higher, you just have to set consumesGesturesInView = NO in your GMSUISettings object.

If you do that, be aware that you will have to deal with events that could make your superview to do stuff when you just want to interact with the map... By that I mean, for example, that dragging a GMSMapView added to a scroll view will scroll the scroll view on drag!

Thrasher answered 7/11, 2013 at 13:37 Comment(0)
L
10
mapView.settings.consumesGesturesInView = YES;

Is also helpful. My parent views were consuming my gesture recognizer

Coupled with

for (UIGestureRecognizer *gestureRecognizer in mapView.gestureRecognizers) {
    [gestureRecognizer addTarget:self action:@selector(handlePan:)];
}


//////



-(IBAction) handlePan:(UIPanGestureRecognizer*)sender {



    if (sender.state == UIGestureRecognizerStateEnded) {
        CGSize size = mapView.frame.size;
        CGPoint tp = CGPointMake(size.width/2, size.height/2);
        CLLocationCoordinate2D loc = [mapView.projection coordinateForPoint:tp];
        [mapView animateToCameraPosition:[GMSCameraPosition cameraWithTarget:loc zoom:mapView.camera.zoom]];



    }


}

it is great! and you don't even need to add your own pan gesture recognizer

Lineup answered 25/2, 2014 at 6:40 Comment(1)
GAH That was it. I've been stuck and tearing my hair out!Ileanaileane
T
3

As it turns out, a GMSMapView instance now owns a GMSBlockingGestureRecognizer which gobbles up all gestures. So there were two choices:

  • Delete this recognizer after loading the GMSMapView (possibly breaking internal functionality that depends on it) (like this); or
  • Attach my own target/action to the recognizer.

Going with this second approach, the following code in the UIViewController's viewDidLoad made things go back to normal:

self.mapView = (RAMapView *)[self.view viewWithTag:1];

for (UIGestureRecognizer *gestureRecognizer in self.mapView.gestureRecognizers) {
    [gestureRecognizer addTarget:self action:@selector(recognizeDragOnMap:)];
}

Honestly, it's an ugly, evil kludge, but it does work. :)

Tambourine answered 2/7, 2013 at 21:15 Comment(0)
S
0

A better alternative would be to set the delegate of your own gesture recogniser and then add the delegate method as follows :

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

It will then work as before.

Shanteshantee answered 22/7, 2013 at 11:13 Comment(1)
Hey Ryan, I did try this, to no effect. Seems the GMSBlockingGestureRecognizer is really aggressive!Tambourine
I
0

Hey there is a delegate method in the Google maps.

- (void)mapView:(GMSMapView *)mapView    didTapAtCoordinate:(CLLocationCoordinate2D)coordinate;
Inwardly answered 13/7, 2015 at 12:16 Comment(0)
S
0

By analysis on google api and other method, I did not get the proper one. The best and sweet answer for this question is by using pan gesture.

add the pan gesture to the mapView as

self.mapView.settings.consumesGesturesInView = false
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self. panHandler(_:)))
self.mapView.addGestureRecognizer(panGesture)

Implementation of pan gesture method as

@objc private func panHandler(_ pan : UIPanGestureRecognizer){

        if pan.state == .ended{
            let mapSize = self.mapView.frame.size
            let point = CGPoint(x: mapSize.width/2, y: mapSize.height/2)
            let newCoordinate = self.mapView.projection.coordinate(for: point)
            print(newCoordinate)
             //do task here
        }
}
Suborn answered 6/4, 2020 at 10:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.