Question

I would like to add a custom image button into the callout of annotations in specific locations. For example searching for starbucks would bring up an annotation marker for starbucks locations, and when the marker is pressed the callout will display a button that then will direct you to another viewcontroller with starbucks information. Right now the annotation displays the address of the location when pressed, how would I change this to displaying a button at custom locations of my choosing? I am very new to xcode and cannot seem to find much helpful information to this relative to how I have designed my app so far. Everything is function as desired except for the fact I do not know where to start to add a button.

here are my ViewControllers

#import "ViewController.h"

@interface ViewController () <UISearchDisplayDelegate, UISearchBarDelegate>

@end

@implementation ViewController {
MKLocalSearch *localSearch;
MKLocalSearchResponse *results;
}

#pragma mark - View Lifecycle

- (void)viewDidLoad
{
[super viewDidLoad];
[self.searchDisplayController setDelegate:self];
[self.ibSearchBar setDelegate:self];

// Zoom the map to current location.
[self.ibMapView setShowsUserLocation:YES];
[self.ibMapView setUserInteractionEnabled:YES];
[self.ibMapView setUserTrackingMode:MKUserTrackingModeFollow];

}

#pragma mark - Search Methods

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {

// Cancel any previous searches.
[localSearch cancel];

// Perform a new search.
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = searchBar.text;
request.region = self.ibMapView.region;

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
localSearch = [[MKLocalSearch alloc] initWithRequest:request];

[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    if (error != nil) {
        [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Map Error",nil)
                                    message:[error localizedDescription]
                                   delegate:nil
                          cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil] show];
        return;
    }

    if ([response.mapItems count] == 0) {
        [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"No Results",nil)
                                    message:nil
                                   delegate:nil
                          cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil] show];
        return;
    }

    results = response;

    [self.searchDisplayController.searchResultsTableView reloadData];
}];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [results.mapItems count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *IDENTIFIER = @"SearchResultsCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:IDENTIFIER];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle            reuseIdentifier:IDENTIFIER];
}

MKMapItem *item = results.mapItems[indexPath.row];

cell.textLabel.text = item.name;
cell.detailTextLabel.text = item.placemark.addressDictionary[@"Street"];

return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.searchDisplayController setActive:NO animated:YES];

MKMapItem *item = results.mapItems[indexPath.row];
[self.ibMapView addAnnotation:item.placemark];
[self.ibMapView selectAnnotation:item.placemark animated:NO];


[self.ibMapView setCenterCoordinate:item.placemark.location.coordinate animated:YES];

[self.ibMapView setUserTrackingMode:MKUserTrackingModeNone];

}

@end


#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface ViewController : UIViewController
@property (strong, nonatomic) IBOutlet UISearchBar *ibSearchBar;
@property (strong, nonatomic) IBOutlet MKMapView *ibMapView;
@end
Was it helpful?

Solution

You could set a button as the callout accessory view ,in the viewForAnnotation method:

 - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
 {

      static NSString *AnnotationIdentifier = @"Annotation";

      if ([annotation isKindOfClass:MKUserLocation.class]) {
         return nil;
      }

      MKPinAnnotationView* pinAnnotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];

      if (!pinAnnotationView)
      {
           pinAnnotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] ;
           pinAnnotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
           pinAnnotationView.canShowCallout = YES;
      }

      return pinAnnotationView;
 }

then you can use the mapView:annotationView:calloutAccessoryControlTapped delegate method to respond when users tap a callout view’s control and, in this case, redirect to another view controller:

 -(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
 {
     InfoController *infoController = [[InfoController alloc] initWithNibName:@"InfoController" bundle:[NSBundle mainBundle]];

     /*
     here you can pass the necessary information to your InfoController
     */

     [self.navigationController pushViewController:infoController  animated:YES];
     [infoController  release];
 }

In this example I take usage of a UINavigationController to manage navigation through my view controllers.

OTHER TIPS

There are great resources on SO on how to customize the callout view, like here and here. You can also look at Apple's Documentation for MKAnnotationView, especially the subclassing notes and their MapCallouts example.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top