开发者

How to capture Tap gesture on MKMapView

I am trying to capture tap event on my MKMapView, this way I can drop a MKPinAnnotation on the point where user tapped. Basically I have a map overlayed with MKOverlayViews (an overlay showing a building) and I would like to give user more information about that Overlay when they t开发者_如何学编程ap on it by dropping a MKPinAnnotaion and showing more information in the callout. Thank you.


You can use a UIGestureRecognizer to detect touches on the map view.

Instead of a single tap, however, I would suggest looking for a double tap (UITapGestureRecognizer) or a long press (UILongPressGestureRecognizer). A single tap might interfere with the user trying to single tap on the pin or callout itself.

In the place where you setup the map view (in viewDidLoad for example), attach the gesture recognizer to the map view:

UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] 
    initWithTarget:self action:@selector(handleGesture:)];
tgr.numberOfTapsRequired = 2;
tgr.numberOfTouchesRequired = 1;
[mapView addGestureRecognizer:tgr];
[tgr release];

or to use a long press:

UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] 
    initWithTarget:self action:@selector(handleGesture:)];
lpgr.minimumPressDuration = 2.0;  //user must press for 2 seconds
[mapView addGestureRecognizer:lpgr];
[lpgr release];


In the handleGesture: method:

- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state != UIGestureRecognizerStateEnded)
        return;

    CGPoint touchPoint = [gestureRecognizer locationInView:mapView];
    CLLocationCoordinate2D touchMapCoordinate = 
        [mapView convertPoint:touchPoint toCoordinateFromView:mapView];

    MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
    pa.coordinate = touchMapCoordinate;
    pa.title = @"Hello";
    [mapView addAnnotation:pa];
    [pa release];
}


I setup a long press (UILongPressGestureRecognizer) in viewDidLoad: but it just detect the only one touch from the first.

Where can i setup a long press to detect all touch? (it means the map ready everytime waiting user touch to screen to push a pin)

The viewDidLoad: method!

- (void)viewDidLoad {
    [super viewDidLoad];mapView.mapType = MKMapTypeStandard;

    UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)];
    [self.mapView addGestureRecognizer:longPressGesture];
    [longPressGesture release];

    mapAnnotations = [[NSMutableArray alloc] init];
    MyLocation *location = [[MyLocation alloc] init];
    [mapAnnotations addObject:location];

    [self gotoLocation];
    [self.mapView addAnnotations:self.mapAnnotations];
}

and the handleLongPressGesture method:

-(void)handleLongPressGesture:(UIGestureRecognizer*)sender {
    // This is important if you only want to receive one tap and hold event
    if (sender.state == UIGestureRecognizerStateEnded)
    {NSLog(@"Released!");
        [self.mapView removeGestureRecognizer:sender];
    }
    else
    {
        // Here we get the CGPoint for the touch and convert it to latitude and longitude coordinates to display on the map
        CGPoint point = [sender locationInView:self.mapView];
        CLLocationCoordinate2D locCoord = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
        // Then all you have to do is create the annotation and add it to the map
        MyLocation *dropPin = [[MyLocation alloc] init];
        dropPin.latitude = [NSNumber numberWithDouble:locCoord.latitude];
        dropPin.longitude = [NSNumber numberWithDouble:locCoord.longitude];
//        [self.mapView addAnnotation:dropPin];
        [mapAnnotations addObject:dropPin];
        [dropPin release];
        NSLog(@"Hold!!");
        NSLog(@"Count: %d", [mapAnnotations count]);
    }   
}


If you want to use a single click/tap in the map view, here's a snippet of code I'm using. (Cocoa and Swift)

let gr = NSClickGestureRecognizer(target: self, action: "createPoint:")
gr.numberOfClicksRequired = 1
gr.delaysPrimaryMouseButtonEvents = false // allows +/- button press
gr.delegate = self
map.addGestureRecognizer(gr)

in the gesture delegate method, a simple test to prefer the double-tap gesture …

func gestureRecognizer(gestureRecognizer: NSGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: NSGestureRecognizer) -> Bool {
  let other = otherGestureRecognizer as? NSClickGestureRecognizer
  if (other?.numberOfClicksRequired > 1) {
    return true; // allows double click
  }

  return false
}

you could also filter the gesture in other delegate methods if you wanted the Map to be in various "states", one of which allowed the single tap/click


For some reason, the UIGestureRecognizer just didn't work for me in Swift. When I use the UIGestureRecognizer way. When I used the touchesEnded method, it returns a MKNewAnnotationContainerView. It seems that this MKNewAnnotationContainerView blocked my MKMapView. Fortunately enough, it's a subview of MKMapView. So I looped through MKNewAnnotationContainerView's superviews till self.view to get the MKMapView. And I managed to pin the mapView by tapping.

Swift 4.1

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    let t = touches.first
    print(t?.location(in: self.view) as Any)
    print(t?.view?.superview?.superview.self as Any)
    print(mapView.self as Any)
    var tempView = t?.view
    while tempView != self.view {
        if tempView != mapView {
            tempView = tempView?.superview!
        }else if tempView == mapView{
            break
        }

    }
  let convertedCoor = mapView.convert((t?.location(in: mapView))!, toCoordinateFrom: mapView)
   let pin =  MKPointAnnotation()
    pin.coordinate = convertedCoor
    mapView.addAnnotation(pin)
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜