質問

I want to create custom callouts on my map. I've tried this right now -

    -(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
    NSLog(@"ANNNOTATION VIEW : %@", view);
    NSLog(@"VIEW ANNOTATION: %@", view.annotation);
    MyMapAnnotationViewController* mapAnnotationViewController = [[MyMapAnnotationViewController alloc]initWithNibName:@"MapAnnotationView" bundle:nil];
    MyLocation* location = (MyLocation*)view.annotation;
    [mapAnnotationViewController setTitle: [location title]];
    [mapAnnotationViewController setRating:3.0];
    [view addSubview:mapAnnotationViewController.view];   
}

-(void)viewWillAppear:(BOOL)animated{
    [_mapView setRegion: _viewRegion];
    for (id<MKAnnotation> annotation in _mapView.annotations) {
        [_mapView removeAnnotation:annotation];
    }
    for(NSDictionary* result in _resultsToPlot){
        NSString* address = someAddr;
        NSString* restaurantTitle = someTitle;
        NSString* description = someDescription;
        NSString* lonLat = someLonLat;
        NSArray *list = [lonLat componentsSeparatedByString:@";"];
        CLLocationCoordinate2D coordinate;
        coordinate.longitude = [[list objectAtIndex: 1] doubleValue];
        coordinate.latitude = [[list objectAtIndex: 0] doubleValue];
        MyLocation *annotation = [[MyLocation alloc] initWithName:restaurantTitle address:address coordinate:coordinate] ;

        [_mapView addAnnotation:annotation];
    }

MyLocation is a subclass of MKAnnotation.

However, this is what things look like now when I click -

enter image description here

So when I click on one pin, my custom view shows AND the annotation shows. I just want the custom view to show. Further, when I click on another pin, the previous custom views are still there.

How do I get it so that the annotation becomes my custom view?

OK - so I did the below and added this-

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(MKAnnotationView*)annotation{
    annotation.canShowCallout = NO;
    return annotation;
}

I am now getting this error-

NSInvalidArgumentException', reason: '-[MyLocation setCanShowCallout:]: unrecognized selector sent to instance 0xcb683e0'
役に立ちましたか?

解決

To disable the built-in callout from displaying, set canShowCallout to NO on the MKPinAnnotationView/MKAnnotationView in the viewForAnnotation delegate method.

The next issue is that currently the code is always creating a new custom callout view and adding it to the selected annotation's view. This is why you get multiple callouts displaying at the same time (the ones on the previously selected annotations are not getting removed).

One solution is to keep a single instance of the custom callout view instead of creating a new one every time an annotation is selected. Then, just add/remove the callout view when an annotation is selected or de-selected.

Declare this single instance as a strong property in the view controller that contains the map view:

@property (nonatomic, strong) MyMapAnnotationViewController* mapAnnotationViewController;

Create the callout instance in viewDidLoad (or viewWillAppear if that works for you) but don't add it as a subview anywhere at this point -- just create it:

self.mapAnnotationViewController = [[MyMapAnnotationViewController alloc...

In didSelectAnnotationView, instead of creating a new callout view instance, tell the existing instance to remove itself from its current superview (if any) and then add it to the new annotation's view:

-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
    NSLog(@"ANNNOTATION VIEW : %@", view);
    NSLog(@"VIEW ANNOTATION: %@", view.annotation);

    [self.mapAnnotationViewController.view removeFromSuperview];

    MyLocation* location = (MyLocation*)view.annotation;
    [self.mapAnnotationViewController setTitle: [location title]];
    [self.mapAnnotationViewController setRating:3.0];
    //Since we are re-using the callout view, 
    //may need to do additional "cleanup" so that the callout
    //shows the new annotation's data.

    [view addSubview:self.mapAnnotationViewController.view];   
}

Finally, you'll need to handle the case where the user de-selects an annotation by tapping on the map (instead of another annotation) and just remove the callout view:

-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
    [self.mapAnnotationViewController.view removeFromSuperview];
}


The viewForAnnotation delegate method should look like this:

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    if (! [annotation isKindOfClass:[MyLocation class]])
    {
        //tell map view to show default view for annotations other than ours
        //(like the user location blue dot)
        return nil;
    }

    MKPinAnnotationView *pav = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"pin"];
    if (pav == nil)
    {
        pav = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"pin"];
        pav.canShowCallout = NO;
    }
    else
    {
        pav.annotation = annotation;
    }

    return pav;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top