0% found this document useful (0 votes)
16 views17 pages

Map Kit in Xamarin.iOS Guide

The document provides an overview of using the Map Kit framework in Xamarin.iOS applications to integrate interactive maps. It covers adding maps, customizing them with annotations and overlays, and utilizing local search capabilities for points of interest. The document includes code examples for implementing these features effectively.

Uploaded by

Dung Le
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views17 pages

Map Kit in Xamarin.iOS Guide

The document provides an overview of using the Map Kit framework in Xamarin.iOS applications to integrate interactive maps. It covers adding maps, customizing them with annotations and overlays, and utilizing local search capabilities for points of interest. The document includes code examples for implementing these features effectively.

Uploaded by

Dung Le
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

iOS Maps

Using Map Kit in Xamarin.iOS Applications

Overview
Maps are a common feature in all modern mobile operating systems. iOS offers mapping support natively
through the Map Kit framework. With Map Kit, applications can easily add rich, interactive maps. These
maps can be customized in a variety of ways, such as adding annotations to mark locations on a map, and
overlaying graphics of arbitrary shapes. Map Kit even has built-in support for showing the current location
of a device.

iOS Maps

Adding a Map

Adding a map to an application is accomplished by adding an MKMapView instance to the view hierarchy,
as shown below:

// map is an MKMapView declared as a class variable


map = new MKMapView (UIScreen.MainScreen.Bounds);
View = map;

MKMapView is a UIView subclass that displays a map. Simply adding the map using the code above
produces an interactive map:
Map Style

MKMapView supports 3 different styles of maps. To apply a map style, simply set the MapType property to
a value from the MapType enumeration. The following screenshot show the different map styles that are
available:
Panning and Zooming

MKMapView includes support for map interactivity features such as:

Zooming via a pinch gesture


Panning via a pan gesture

These features can be enabled or disabled by simply setting the ZoomEnabled and ScrollEnabled
properties of the MKMapView instance, where the default value is true for both. For example, to display a
static map, simply set the appropriate properties to false:

map.ZoomEnabled = false;
map.ScrollEnabled = false;

User Location

In addition to user interaction, MKMapView also has built-in support for displaying the location of the device.
It does this internally by using the Core Location framework. However, enabling this is as simple as setting
the ShowsUserLocation property to true:

map.ShowsUserLocation = true;

When user location is enabled, the first time the application runs, the user will be prompted to allow location
services for the application, as shown below:
Annotations

MKMapView also supports displaying images, known as annotations, on a map. These can be either
custom images or system-defined pins of various colors. For example, the following screenshot shows a
map with a both a pin and a custom image:
Adding an annotation

An annotation itself has two parts:

The MKAnnotation object, which includes model data about the annotation, such as the title and
location of the annotation.
The MKAnnotationView , which contains the image to display and optionally a callout that is shown
when the user taps the annotation.
Map Kit uses the iOS delegation pattern to add annotations to a map, where the Delegate property of the
MKMapView is set to an instance of an MKMapViewDelegate. It is this delegate's implementation that is
responsible for returning the MKAnnotationView for an annotation.

To add an annotation, first the annotation is added by calling AddAnnotation on the MKMapView
instance:

// add an annotation
map.AddAnnotation (new MKPointAnnotation (){
Title="MyAnnotation",
Coordinate = new CLLocationCoordinate2D (42.364260, -71.120824)
});

When the location of the annotation becomes visible on the map, the MKMapView will call its delegate's
GetViewForAnnotation method to get the MKAnnotationView to display.

For example, the following code returns a system-provided MKPinAnnotationView:

string pId = "PinAnnotation";

public override MKAnnotationView GetViewForAnnotation (MKMapView mapView,


NSObject annotation)
{
if (annotation is MKUserLocation)
return null;

// create pin annotation view


MKAnnotationView pinView =
(MKPinAnnotationView)mapView.DequeueReusableAnnotation (pId);

if (pinView == null)
pinView = new MKPinAnnotationView (annotation, pId);

((MKPinAnnotationView)pinView).PinColor = MKPinAnnotationColor.Red;
pinView.CanShowCallout = true;

return pinView;
}
Reusing Annotations

To conserve memory, MKMapView allows annotation view's to be pooled for reuse, similar to the way table
cells are reused. Obtaining an annotation view from the pool is done with a call to
DequeueReusableAnnotation:

MKAnnotationView pinView =
(MKPinAnnotationView)mapView.DequeueReusableAnnotation (pId);

Showing Callouts

As mentioned earlier, an annotation can optionally show a callout. To show a callout simply set
CanShowCallout to true on the MKAnnotationView. This results in the annotation's title being
displayed when the annotation is tapped, as shown:
Customizing the Callout

The callout can also be customized to show left and right accessory views, as shown below:

pinView.RightCalloutAccessoryView = UIButton.FromType
(UIButtonType.DetailDisclosure);
pinView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile
("monkey.png"));

This code results in the following callout:


To handle the user tapping the right accessory, simply implement the
CalloutAccessoryControlTapped method in the MKMapViewDelegate:

public override void CalloutAccessoryControlTapped (MKMapView mapView,


MKAnnotationView view, UIControl control)
{
...
}

Overlays

Another way to layer graphics on a map is using overlays. Overlays support drawing graphical content that
scales with the map as it is zoomed. iOS provides support for several types of overlays, including:

Polygons - Commonly used to highlight some region on a map.


Polylines - Often seen when showing a route.
Circles - Used to highlight a circular area of a map.

Additionally, custom overlays can be created to show arbitrary geometries with granular, customized
drawing code. For example, weather radar would be a good candidate for a custom overlay.

Adding an Overlay

Similar to annotations, adding an overlay involves 2 parts:

Creating a model object for the overlay and adding it to the MKMapView .
Creating a view for the overlay in the MKMapViewDelagate .
The model for the overlay can be any MKShape subclass. Xamarin.iOS includes MKShape subclasses for
polygons, polylines and circles, via the MKPolygon, MKPolyline and MKCircle classes respectively.

For example, the following code is used to add an MKCircle:

var circleOverlay = MKCircle.Circle (mapCenter, 1000);


map.AddOverlay (circleOverlay);

The view for an overlay is an MKOverlayView instance that is returned by the GetViewForOverlay in
the MKMapViewDelegate. Each MKShape has a corresponding MKOverlayView that knows how to
display the given shape. For MKPolygon there is MKPolygonView. Similarly, MKPolyline corresponds
to MKPolylineView, and for MKCircle there is MKCircleView.

For example, the following code returns an MKCircleView for an MKCircle:

public override MKOverlayView GetViewForOverlay (MKMapView mapView, NSObject


overlay)
{
var circleOverlay = overlay as MKCircle;
var circleView = new MKCircleView (circleOverlay);
circleView.FillColor = UIColor.Blue;
return circleView;
}

This displays a circle on the map as shown:


Local Search

iOS 6.1 includes a local search API with Map Kit, which allows asynchronous searches for points of interest
in a specified geographic region.

To perform a local search, an application must follow these steps:

1. Create MKLocalSearchRequest object.


2. Create an MKLocalSearch object from the MKLocalSearchRequest .
3. Call the Start method on the MKLocalSearch object.
4. Retrieve the MKLocalSearchResponse object in a callback.

The local search API itself provides no user interface. It doesn’t even require a map to be used. However,
to make practical use of local search, an application needs to provide some way to specify a search query
and display results. Additionally, since the results will contain location data, it will often make sense to show
them on a map.

Adding a Local Search UI

For example, one way to accept search input is with a UISearchBar, which can be used in conjunction
with a UISearchDisplayController to display results in a table.

The following code adds a UISearchBar and UISearchController in the ViewDidLoad method of
MapDemoViewController:

// create search controller


searchBar = new UISearchBar (new RectangleF (0, 0, View.Frame.Width, 50)) {
Placeholder = "Enter a search query"
};
searchController = new UISearchDisplayController (searchBar, this);
searchController.Delegate = new SearchDelegate (map);
searchController.SearchResultsSource = new SearchSource (searchController,
map);
View.AddSubview (searchBar);

This results in a search bar displayed over the map as shown below (the SearchDelegate and
SearchSource will be implemented shortly):
Implementing a UISearchDisplayDelegate

When using a UISearchDisplayController, search input from the associated UISearchBar is


captured in a UISearchDisplayDelegate. For the case of a local search, this is where the search can
be initiated, as shown in the following code:

class SearchDelegate : UISearchDisplayDelegate


{
MKMapView map;

public SearchDelegate (MKMapView map)


{
this.map = map;
}

public override bool ShouldReloadForSearchString (UISearchDisplayController


controller, string forSearchString)
{
// create search request
var searchRequest = new MKLocalSearchRequest ();
searchRequest.NaturalLanguageQuery = forSearchString;
searchRequest.Region = new MKCoordinateRegion
(map.UserLocation.Coordinate, new MKCoordinateSpan (0.25, 0.25));

// perform search
var localSearch = new MKLocalSearch (searchRequest);
localSearch.Start (delegate (MKLocalSearchResponse response, NSError
error) {
if (response != null && error == null) {
((SearchSource)controller.SearchResultsSource).MapItems =
response.MapItems.ToList();
controller.SearchResultsTableView.ReloadData();
} else {
Console.WriteLine ("local search error: {0}", error);
}
});

return true;
}
}

Displaying the Search Results

After creating the MKLocalSearch object and using it to issue a search for an MKLocalSearchRequest,
the results are retrieved in a callback passed to the Start method of the MKLocalSearch object. The
results are returned in an MKLocalSearchResponse object containing an array of MKMapItem objects.

The UISearchDisplayController encapsulates a UITableView to display search results and


includes a SearchResultsSource property, which is a UITableViewSource.

The following code implements a UITableViewSource to show the map items in the UITableView of
the UISearchDisplayController:

class SearchSource : UITableViewSource


{
static readonly string mapItemCellId = "mapItemCellId";
UISearchDisplayController searchController;
MKMapView map;

public List<MKMapItem> MapItems { get; set; }

public SearchSource (UISearchDisplayController searchController, MKMapView


map)
{
this.searchController = searchController;
this.map = map;

MapItems = new List<MKMapItem> ();


}

public override int RowsInSection (UITableView tableview, int section)


{
return MapItems.Count;
}

public override UITableViewCell GetCell (UITableView tableView, NSIndexPath


indexPath)
{
var cell = tableView.DequeueReusableCell (mapItemCellId);

if (cell == null)
cell = new UITableViewCell ();

cell.TextLabel.Text = MapItems [indexPath.Row].Name;


return cell;
}

public override void RowSelected (UITableView tableView, NSIndexPath


indexPath)
{
searchController.SetActive (false, true);

// add item to map


CLLocationCoordinate2D coord = MapItems
[indexPath.Row].Placemark.Location.Coordinate;
map.AddAnnotation (new MKPointAnnotation () {
Title = MapItems [indexPath.Row].Name,
Coordinate = coord
});

map.SetCenterCoordinate (coord, true);


}
}

The implementation above adds an annotation to the map when an item is selected from the results, as
shown below:

Summary
This article examined the Map Kit framework for iOS. First, it looked at how the MKMapView class allows
interactive maps to be included in an application. Then it demonstrated how to further customize maps
using annotations and overlays. Finally, it examined the local search capabilities that were added to Map
Kit with iOS 6.1, showing how to use perform location based queries for points of interest and add them to
a map.

You might also like