1

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
user3492592
  • 89
  • 12

2 Answers2

1

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.

Hari
  • 1,509
  • 15
  • 34
  • thanks for your response, I am just having a bit of trouble understanding where the first bit of code should be placed. Where would my viewForAnnotation method be located? I cant seem to find it. – user3492592 Apr 04 '14 at 09:28
  • Edited my answer with the `mapView:viewForAnnotation` method code. You should locate thit inside `ViewController.m` ... – Hari Apr 04 '14 at 09:57
  • I am having difficulty getting this code to function properly. I put both methods into my ViewController.m file but I am receiving error messages saying detalview is an undeclared identifier. I am completely new to xcode I apologize for my lack of knowledge. – user3492592 Apr 05 '14 at 00:28
  • No need to apologize. Do you have a class named DetailViewController? Have you imported it correctly in your class? – Hari Apr 05 '14 at 09:49
  • no i do not have a class named detail view controller. The button should direct me to InfoController which is the next viewController in my story board. InfoController will be filled with information that is specific to the location that was selected with the button in the call out. – user3492592 Apr 07 '14 at 04:44
  • then you should instantiate `InfoController` and not `DetailViewController`, that was just for example with the following explanations... I'm modifying the code for you. – Hari Apr 08 '14 at 09:56
0

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.

Community
  • 1
  • 1
mstottrop
  • 589
  • 5
  • 21