Displaying a Callout

It is sometimes necessary to show more information about features being displayed on a map. For instance, a user may want to see the business hours of a restaurant, or the price of a house on sale. This information can be displayed very effectively using a callout.

A callout is anchored to a geographic location on the map. As a user navigates the map, the callout remains anchored to the same location. The callout can display text in two sections: title and detail. The callout also has an accessory button. This accessory button can be used to bring up another view to show more information about the feature. From version 1.8 onwards, the callout can also display an image of 40x40 pixels to the left of the text . You can also completely change the layout of the callout by embedding a custom view.

Standard callout
Callout using a custom view

A callout is an instance of AGSCallout. A map has only one callout at any given time which can be accessed through the callout property on AGSMapView.

Displaying a callout

A map displays a callout whenever a user taps on a graphic, provided that AGSGraphic object has a valid infoTemplateDelegate. The infoTemplateDelegate specifies what content needs to be displayed in the callout. Similarly, a map also displays a callout when a user taps on the GPS location symbol, provided the map's AGSGPS object has a valid infoTemplateDelegate

You can also display a callout programatically using methods on AGSMapView. The showCalloutAtPoint: method allows you to display the callout at any geographic location on the map. The showCalloutAtPoint:forGraphic:animated: method allows you display the callout for a particular graphic.

Displaying content in a callout

You can provide the Information to be displayed in a callout in two ways -

Directly modifying a callout's properties

You would typically only assign values directly to AGSCallout properties when you display a callout programatically for an arbitrary location on the map. When doing so, you can modify the title , detail , image , and/or customView properties to provide the content that needs to be displayed.

//Specify the callout's contents
mapView.callout.title = @"<title>";
mapView.callout.detail = @"<detail>";
mapView.callout.image = [UIImage imageNamed:@"<my_image.png>"];

//Display the callout
AGSPoint* point = ...;
[mapView showCalloutAtPoint: point];

Using an infoTemplateDelegate

In most situations, however, a callout is displayed in response to user interaction. For instance, when the user taps on the GPS location symbol, or when the user taps on a graphic in a graphics layer. In such cases, it is more convenient to provide information to the callout using an infoTemplateDelegate.

The delegate needs to implement a well known protocol in order to provide the contents to be displayed. For information on how to use an infoTemplateDelegate with graphics, refer to Displaying attribute information in the callout. For information on how to use an infoTemplateDelegate with the GPS location, refer to Displaying location information in the callout

You may also decide to programatically display the callout for a graphic. If the graphic has an infoTemplateDelegate, it will be used to display information in the callout. Otherwise, you will need to specify the information by directly modifying the callout's properties as described in the previous section.

Regardless of how the callout is displayed, programatically or automatically in response to user interaction, the map's calloutDelegate is always consulted to check whether the callout should be shown for a graphic or the GPS location symbol. Thus, you can control whether or not a callout should be displayed by designating one of your classes as the map's calloutDelegate. Whenever the callout displayed, the same calloutDelegate is informed so that it can perform some additional operations.

@interface MyDelegate : NSObject <AGSMapViewCalloutDelegate> 
  ...
  - (BOOL) mapView: (AGSMapView *) mapView shouldShowCalloutForGraphic: (AGSGraphic *) graphic ;
  - (void) mapView: (AGSMapView *) mapView didShowCalloutForGraphic: (AGSGraphic *) graphic ;

@end

@implementation MyDelegate

- (BOOL) mapView: (AGSMapView *) mapView shouldShowCalloutForGraphic: (AGSGraphic *) graphic {
  //invoked when a user taps on a graphic
  //decide if a callout should be shown for the graphic
}

- (void) mapView: (AGSMapView *) mapView didShowCalloutForGraphic: (AGSGraphic *) graphic {
  //perform some additional operations after callout is displayed
}

Responding to the callout's accessory button

When a user taps on the accessory button in the callout, the map's calloutDelegate is informed. Depending upon whether the callout was displayed in response to a tap on the map , a graphic, or the GPS location symbol, one of three methods of the calloutDelegate will be invoked -

- (void) mapView: (AGSMapView *) mapView didClickCalloutAccessoryButtonAtPoint:	(AGSPoint *) point 

- (void) mapView: (AGSMapView *) mapView didClickCalloutAccessoryButtonForGraphic: (AGSGraphic *) graphic

- (void) mapView: (AGSMapView *) mapView didClickCalloutAccessoryButtonForGPS: (AGSGPS *) gps

You can implement the relevant methods in your delegate and then display a secondary view to show more information, or perform some additional operation.

Customizing a callout's appearance

You can change some visual properties of the callout such as its background color, width, text color, visibility and appearance of the accessory button etc. These elements are exposed as properties on the AGSCallout object.

//don't show the accessory button
mapView.callout.accessoryButtonHidden = YES;

//or use a custom image for the accessory button
mapView.callout.accessoryButtonType = UIButtonTypeCustom;
mapView.callout.accessoryButtonImage = [UIImage imageNamed:@"<my_image.png>"];

//Change color of background, title and detail
mapView.callout.color = [UIColor blueColor];
mapView.callout.titleColor = [UIColor redColor];
mapView.callout.detailColor = [UIColor greenColor];

Dismissing a callout

A callout is dismissed automatically by the map when a user taps on the map, away from the callout. To dismiss a callout programatically, you simply need to enable its hidden property.

mapView.callout.hidden = YES;

9/14/2011