How can I tell if singleTap or annotation on mapView mapbox was clicked?

IOS requirement for mapBox. (I'm not talking about MKMapView) how can we determine if singleTap or the annotation on mapView was clicked? I need singleTap to be processed only in an empty area of โ€‹โ€‹the map (without contacts), and didSelectAnnotation is called when I click on a contact.

But I found on android we have such a method

mapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() { public void onMapClick(@NonNull LatLng point) { Toast.makeText(getActivity(),"on Tap "+point.getLatitude(),Toast.LENGTH_LONG).show(); } }); 

and at the same time

mapboxMap.setInfoWindowAdapter(new MapboxMap.InfoWindowAdapter() { ... }) displays the annotation.

Do we not have such a concept in iOS?

The real problem in iOS is when I add singleTapGesture to mapView of Mapbox

 UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; [self.mapView addGestureRecognizer:singleTapGesture]; 

The delegate method mapView mapbox will not call.

 - (nullable UIView <MGLCalloutView> *)mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id <MGLAnnotation>)annotation; 

to make sure the delegate method should be called, then I don't need to use singleTapGesture

Here the situation is either this or that, but as needed I needed both.

Waiting for any decision. Thanks,

+6
source share
6 answers

I made another workaround here

I cloned release-ios-v3.3.0 and created the package using the Create SDK and added one delegate to MGLMapvViewDelegate.h as I need something like that. -(void)mapView:(MGLMapView *)mapView tapOnNonAnnotationAreaWithPoints:(CGPoint)points

and in MGLMapView.mm I updated code like this,

 else{ if(self.selectedAnnotation) [self deselectAnnotation:self.selectedAnnotation animated:YES]; else if([self.delegate respondsToSelector:@selector(mapView:tapOnNonAnnotationAreaWithPoints:)]) [self.delegate mapView:self tapOnNonAnnotationAreaWithPoints:tapPoint]; } 

which is in the method -(void)handleSingleTapGesture:(UITapGestureRecognizer *)singleTap .

It works for me, as I can detect a single click on an area without annotation. later I convert past points to geocoordinates, so I work with recently tapped coordinates.

Note

  • The new library size is about 48.7 MB , where 38.3 MB was the loaded library.
  • The style does not work properly, you can see in the attached file enter image description here enter image description here (Tried with a different style url, but none of the same as the previous one)
  • I feel the lack of application performance, scaling and panning is not as smooth as the dynamic library provided by the Mapbox guys.

I'm still studying. lemme know if you want to check / research me.

Accept this answer if it is helpful.

Thanks,

Happy coding.

+2
source

Try it fast 3

 //determined is Point inner to realm polygons func determinedInPoligon(point:CLLocationCoordinate2D, poligon:[CLLocationCoordinate2D]) -> Bool { var result:Bool = false var j = poligon.count - 1 for i in 0 ..< poligon.count { if (poligon[i].longitude < point.longitude && poligon[j].longitude >= point.longitude || poligon[j].longitude < point.longitude && poligon[i].longitude >= point.longitude) && (poligon[i].latitude + (point.longitude - poligon[i].longitude) / (poligon[j].longitude - poligon[i].longitude) * (poligon[j].latitude - poligon[i].latitude) < point.latitude) { result = !result; } j = i; } return result } func squareFrom(location: CGPoint, radius: Double) -> CGRect {//return rect with CGPoint center and radius let length = radius return CGRect(x: Double(location.x - CGFloat(length / 2)), y: Double(location.y - CGFloat(length / 2)), width: length, height: length) } 

function descriptor

 func handleTap(_ gesture: UITapGestureRecognizer) { // Get the CGPoint where the user tapped. let spot = gesture.location(in: mapView) let my_features = mapView.visibleFeatures(at: spot) let strZoomValue = mapView.zoomLevel > 15 ? "6" : "4" //the feature structur object value not equal annotation object for value in my_features.enumerated() {// feature items if value.element is MGLPointAnnotation { for annot in (mapView.annotations?.enumerated())! { // annotation items if annot.element is MGLPointAnnotation { //rounded lat and lng value var arr_cllocation = [CLLocationCoordinate2D]() for cllocation in [(annot.element as! MGLPointAnnotation).coordinate, (value.element as! MGLPointAnnotation).coordinate] { let strLat = String(format: "%."+strZoomValue+"f", cllocation.latitude) let strLon = String(format: "%."+strZoomValue+"f", cllocation.longitude) arr_cllocation.append( CLLocationCoordinate2D(latitude: CLLocationDegrees(strLat)!, longitude: CLLocationDegrees(strLon)!) ) } if arr_cllocation.count == 2 && memcmp(&arr_cllocation[0], &arr_cllocation[1], MemoryLayout<CLLocationCoordinate2D>.size) == 0 {// 0 if equal object // to do custom popup view let instViewPopupLineClass = UINib(nibName: "ViewPopupBase", bundle: nil).instantiate(withOwner: self, options: nil).first as! UIView for objectInst in instViewPopupLineClass.subviews.enumerated() { if objectInst.element is UILabel { let asdasdas = (annot.element as! MGLPointAnnotation).subtitle (objectInst.element as! UILabel).text = asdasdas MyCustomPopup(customView: instViewPopupLineClass, positionXY: spot) break } } } } } //for end } } } 

OR inaccurate method, but working;)

 func handleTap(_ gesture: UITapGestureRecognizer) {// Get the CGPoint where the user tapped. let spot = gesture.location(in: mapView) let cllcordinatTap = mapView.convert(spot, toCoordinateFrom: mapView) //for determined zoom scala let deltScalaMap = abs(self.mapView.maximumZoomLevel - self.mapView.zoomLevel) //The large is zoom maps, then smal size is tap location, and vice versa. let checkScalaMap = deltScalaMap == 0 ? 1 : deltScalaMap let _rect = squareFrom(location: CGPoint(x: cllcordinatTap.latitude, y: cllcordinatTap.longitude), radius: 0.00005 * checkScalaMap) for annot in (mapView.annotations?.enumerated())! { if annot.element is MGLPointAnnotation { let _cordinatCurrentAnnotation = (annot.element as! MGLPointAnnotation).coordinate if determinedInPoligon(point: _cordinatCurrentAnnotation, poligon: [CLLocationCoordinate2D(latitude: CLLocationDegrees(_rect.minX), longitude: CLLocationDegrees(_rect.minY)), CLLocationCoordinate2D(latitude: CLLocationDegrees(_rect.maxX), longitude: CLLocationDegrees(_rect.minY)), CLLocationCoordinate2D(latitude: CLLocationDegrees(_rect.maxX), longitude: CLLocationDegrees(_rect.maxY)), CLLocationCoordinate2D(latitude: CLLocationDegrees(_rect.minX), longitude: CLLocationDegrees(_rect.maxY)) ]) { // to do, if tap MGLPointAnnotation, annot.element } } } } 
+1
source

I think the method -(void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id<MGLAnnotation>)annotation will solve your problem for selecting annotation.

0
source

I tried a sample project for your question and it works well.

.h

 #import <UIKit/UIKit.h> #import <MapKit/MapKit.h> @interface ViewController : UIViewController<MKMapViewDelegate> @property (strong, nonatomic) IBOutlet MKMapView *mapTapAnnotation; @end 

.m

 #import "ViewController.h" @interface ViewController () @end @implementation ViewController @synthesize mapTapAnnotation; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self setMapViewWithAnnnoationPin]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } -(void)setMapViewWithAnnnoationPin { mapTapAnnotation.showsUserLocation = YES; mapTapAnnotation.mapType = MKMapTypeHybrid; CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(12.900988, 80.227930); MKCoordinateSpan span = MKCoordinateSpanMake(0.005, 0.005); MKCoordinateRegion region = {coord, span}; MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init]; [annotation setCoordinate:coord]; [annotation setTitle:@"Single Tap"]; //You can set the subtitle too [mapTapAnnotation setRegion:region]; [mapTapAnnotation addAnnotation:annotation]; UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(detectSingleTap)]; tapGesture.numberOfTapsRequired = 1; [mapTapAnnotation addGestureRecognizer:tapGesture]; } -(void)detectSingleTap { NSLog(@"Finded the single tap on map view"); } - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view { NSLog(@"The single tap annotation pin point is - %ld",(long)view.tag); } 

Print Output

 Finded the single tap on map view The single tap annotation pin point is - 0 
0
source

Here I got some workaround that helped work with my requirement. According to my need, I can get a single detection on both gadget marker markers, as well as in an empty area of โ€‹โ€‹the map

I created a category for MGLMapView, (MGLMapView + EDCMapboxView) and overrides sensory methods

 -touchesBegan:withEvent: -touchesMoved:withEvent: -touchesEnded:withEvent: -touchesCancelled:withEvent: 

MGLMapView + EDCMapboxView.h

 @protocol EDCMapboxViewDelegate <NSObject> @optional - (void)mapboxViewDidCreateNewTicket:(MGLMapView*)mapView; @end @interface MGLMapView (EDCMapboxView) @property (assign, nonatomic) BOOL shouldCreateNewTicket; @property (weak, nonatomic) id <EDCMapboxViewDelegate> mapboxDelegate; @end 

MGLMapView + EDCMapboxView.m

 @implementation MGLMapView (EDCMapboxView) @dynamic mapboxDelegate; #pragma mark -- Accessor - (BOOL)shouldCreateNewTicket { return [objc_getAssociatedObject(self, @selector(shouldCreateNewTicket)) boolValue]; } - (void)setShouldCreateNewTicket:(BOOL)flag { objc_setAssociatedObject(self, @selector(shouldCreateNewTicket), @(flag), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(id<EDCMapboxViewDelegate>)mapboxDelegate{ return objc_getAssociatedObject(self, @selector(mapboxDelegate)); } - (void)setMapboxDelegate:(id<EDCMapboxViewDelegate>)mapboxDelegate{ objc_setAssociatedObject(self, @selector(mapboxDelegate), mapboxDelegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } #pragma mark -- Overrided method for UIResponder - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{ NSLog(@"touchesBegan"); } - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{ NSLog(@"touchesMoved"); self.shouldCreateNewTicket = NO; } - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{ NSLog(@"touchesEnded"); } - (void)touchesCancelled:(nullable NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event{ NSLog(@"touchesCancelled"); [self createNewTicket]; } - (void)createNewTicket{ if(self.shouldCreateNewTicket){ NSLog(@"Allowed to Create New ticket"); // Tells that tap is on empty area. if([self.mapboxDelegate respondsToSelector:@selector(mapboxViewDidCreateNewTicket:)]){ [self.mapboxDelegate mapboxViewDidCreateNewTicket:self]; } } else{ NSLog(@"Not allowed to create New ticket"); // Tells tap is on annotation marker. self.shouldCreateNewTicket = YES; } } 

EDCMapboxViewController.m

 - (void)viewDidLoad { [super viewDidLoad]; self.mapView.shouldCreateNewTicket = YES; ..... ....... ........ } - (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation { NSLog(@"annotationCanShowCallout"); // Tells that annotation is tapped, then do not allow to create ticket. self.mapView.shouldCreateNewTicket = NO; return YES; } - (void)mapboxViewDidCreateNewTicket:(MGLMapView*)mapView{ // Tells that tap is on empty area and not on marker, then allow to create ticket. } 

It worked for me, hope it helps you and the guys. Thanks.

0
source

This is how I solved it, you should get the concept.

 func onMapSingleTapped(recognizer: UITapGestureRecognizer) { let viewLocation: CGPoint = recognizer.locationInView(map) // check if any annotations are hit if(map.annotations != nil) { for annotation in map.annotations! { if(annotation.isKindOfClass(MapCheckInAnnotation)) { let pin: MapCheckInAnnotation = annotation as! MapCheckInAnnotation if let pinView = pin.view { print("pinview \(pinView.frame.origin)") // check if hit pin instead of just map if(viewLocation.x >= pinView.frame.origin.x && viewLocation.x < pinView.frame.origin.x + pinView.frame.width) { if(viewLocation.y >= pinView.frame.origin.y && viewLocation.y < pinView.frame.origin.y + pinView.frame.height) { mapView(map, didSelectAnnotationView: pinView) return } } } } } } // nope, no annotations were clicked let mapLocation: CLLocationCoordinate2D = map.convertPoint(viewLocation, toCoordinateFromView: map) print("onMapSingleTapped \(mapLocation)") } 
0
source

All Articles