Skip To Content ArcGIS for Developers Sign In Dashboard

Displaying a callout

It is sometimes necessary to show more information about features displayed on a map. For instance, a user may want to see a restaurant's business hours or sale price of a house. 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 show another view that gives more information about the feature. The callout can also display an image of 40x40 pixels to the left of the text.

Standard callout
Standard callout

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

Customizing a callout's appearance

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

//don't show the accessory button
mapView.callout.accessoryButtonHidden = true
//or use a custom image for the accessory button
mapView.callout.accessoryButtonType = .Custom
mapView.callout.accessoryButtonImage = UIImage(named: "<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()

Alternatively, you can completely change look and feel of the callout by setting the customView property to embed your own view. The example below shows a callout containing a map, some buttons, and few lines of text.

Callout using a custom view
Callout using a custom view

Displaying a callout in response to a tap on a feature

Whenever a user taps on a feature in the map, the callout's delegate is consulted to check whether or not a callout should be displayed for that feature. The delegate not only controls the display of the callout, it can also customize the information presented in the callout by modifying properties on the AGSCallout object.


The feature must belong to a layer that supports hit-testing. These layers implement the <AGSHitTestable> protocol, for example, AGSGraphicsLayer. If a layer does not support hit-testing, the map cannot detect whether a user tapped on a feature, and consquently cannot initiate the process to display a callout for it.

By default, the callout's delegate is uninitialized. This implies that there is no information to show in the callout and the map won't display a callout even when a user taps on any feature. To display a callout, you need to set one of your classes as the callout's delegate. You do this by making your class (typically a view controller) adopt the <AGSCalloutDelegate> protocol and impelementing one ore more methods defined in the protocol. In the example below, we implement the callout:willShowForFeature:layer:mapPoint: method to display the feature's name and address in the callout -

class MyViewController:UIViewController, AGSCalloutDelegate {

 func callout(callout: AGSCallout!, willShowForFeature feature: AGSFeature!, layer: AGSLayer!, mapPoint: AGSPoint!) -> Bool {
  //Specify the callout's contents
  mapView.callout.title = feature.attributeAsStringForKey("Name")
  mapView.callout.detail = feature.attributeAsStringForKey("Address")
  mapView.callout.image = UIImage(named: "<my_image.png>") 
  return true

Note that the method implementation returns YES at the end. This instructs the map to go ahead and display a callout. If you don't want to display the callout for some features, for example if they are missing the address attribute, you can return NO.

If you want to temporarily disable callout for all features on the map, you can set the allowCallout property on AGSMapView to NO. When you do this, the map no longer consults the callout's delegate whenever a user taps on a feature.

There will be times when you want to customize the information in the callout depending upon the type of feature for which it is being displayed. To make handling such situations easier, you can specify callout delegates on a layer-by-layer basis, instead of centrally on the callout object. To do this, you need to set one of your classes as the layer's calloutDelegate, adopt the <AGSLayerCalloutDelegate> protocol, and implement the callout:willShowForFeature:layer:mapPoint: method.

func callout(callout: AGSCallout!, willShowForFeature feature: AGSFeature!, layer: AGSLayer!, mapPoint: AGSPoint!) -> Bool {
	//Specify the callout's contents
	return true
The map gives precedence to the layer's callout delegate if it is available. Otherwise the map falls back to the callout's delegate as described earlier in this section. If you want to temporarily disable callout for all features in a particular layer, you can set the allowCallout property on the layer to NO.

If you're only interested in showing a feature's attribute values in the callout, the API provides an AGSCalloutTemplate class, which is a convenient implementation of the <AGSLayerCalloutDelegate> protocol. AGSCalloutTemplate allows you to specify title and detail text for the callout using tokens. Tokens are attribute keys enclosed by ${ } characters. Attributes keys are automatically replaced by attribute values for the graphic when the callout is displayed.

let template = AGSCalloutTemplate()
template.titleTemplate = "${CITY_NAME}"; //show the value for attribute key 'CITY_NAME'
template.detailTemplate = "${POPULATION}"; //show the value for attribute key 'POPULATION'
let layer:AGSGraphicsLayer = ...
layer.calloutDelegate = template


AGSCalloutTemplate is best suited for attribute values that are strings. It does not provide the ability to localize numbers or dates. Furthermore, it does not provide the flexibility of specifying an image or a custom view for the callout.

Displaying a callout programmatically

The map has a property called allowCallout that specifies whether or not the it will attempt to display a callout when a user taps on a feature on the map. By default, this property is set to YES, in which case the map first checks if the layer that the feature belongs contains a valid calloutDelegate. This callout delegate is then given the opportunity

Although the map has the ability to automatically display a callout whenever a user taps on a feature as described above, it is sometimes useful to initiate the display of the callout through code. For example, you may want to zoom to a feature and display a callout on it in response to a tap on a table view cell.

You can display a callout programmatically using methods on AGSCallout. The showCalloutAt:screenOffset:animated: method allows you to display the callout at any arbitrary location on the map. The showCalloutAtPoint:forFeature:animated: method allows you display the callout for a particular feature.

Responding to a tap on the callout's Accessory button

The callout is best suited for displaying a small amount of information on the map; one or two lines of text. However, there will be times when more detailed information will need to be displayed. To achieve this, the callout contains an optional accessory button that developers can use to present additional view controllers.

When the accessory button is tapped, the callout's delegate is informed by invoking the didClickAccessoryButtonForCallout: method. Depending upon whether the callout was originally displayed for a graphic, the location symbol, or an arbitrary location on the map, the callout's representedObject property contains the relevant id<AGSFeature>, AGSLocationDisplay, or AGSPoint objects

func didClickAccessoryButtonForCallout(callout: AGSCallout!) {
	//Handle tap on the accessory button when callout was displayed for a graphic

Dismissing a callout

A callout is automatically dismissed, when a user taps on the map away from the callout. However, if you want to dismiss a callout programatically, you can invoke its dismiss method.


See Also