Displaying a Map of the Current Location with MonoTouch

Today, I started spiking on displaying maps in iOS using MonoTouch. I wanted to discover the minimum amount of code needed to get the users current location via the iOS GPS services and then display that location on the a map.

To get the devices current location you need an instance of CLLocationManager found in the MonoTouch.CoreLocation namespace. The location manager accesses the actual hardware on the device and can be a real power drain, so you want to use it as little as possible.

using System;
using MonoTouch.CoreLocation;

namespace App.UI
{
	public class LocationService
	{
		private CLLocationManager locationManager;

		public LocationService()
		{
			locationManager = new CLLocationManager();
		}

		public CLLocationCoordinate2D GetCurrentLocation()
		{
			//dirty for now just to get some info.
			locationManager.StartUpdatingLocation();
			while(locationManager.Location == null);
			locationManager.StopUpdatingLocation();

			return locationManager.Location.Coordinate;
		}
	}
}

This simple service shows the absolute minimum needed to retrieve the devices current location. First, we tell the manager to StartUpdatingLocation which will trigger a dialog to the user requesting access to the devices location services. The current location is then available from the Location property. It takes a few seconds to populate though, which is why most of the demo code you will find uses a LocationDelegate to consume the data. I wanted something a little simpler because I don't actually need updates to the location, so I spin until the Location property is not null. I then grab the Coordinate from the Location property and tell the manager to StopUpdatingLocation.

On a side note the user can disable location globally on the device. You can check to see if the user has done so via the static member LocationServicesEnabled. You could use this to display a dialog to ask the user to put in a zip code maybe as an alternative.

To display the location on a map for the user you will need to use the MKMapView from the MonoTouch.MapKit namespace. I have chosen to create a MapViewController class that extends UIViewController to wrap all this code in.

using System;
using System.Drawing;

using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.MapKit;
using MonoTouch.CoreLocation;

namespace App.UI
{
	public class MapViewController : UIViewController
	{
		private LocationService locationService;
		private MKMapView mapView;

		public ProductsViewController(LocationService locationService)
		{
			this.locationService = locationService;
		}

		public override void ViewDidLoad()
		{
			base.ViewDidLoad();

			var currentLocation = locationService.GetCurrentLocation();
			var visibleRegion = BuildVisibleRegion(currentLocation);

			mapView = BuildMapView(true);
			mapView.SetRegion(visibleRegion, true);

			this.View.AddSubview(mapView);
		}

		private MKMapView BuildMapView(bool showUserLocation)
		{
			var view = new MKMapView()
			{
				ShowsUserLocation = showUserLocation
			};

			view.SizeToFit();
			view.Frame = new RectangleF(0, 0, this.View.Frame.Width, this.View.Frame.Height);
			return view;
		}

		private MKCoordinateRegion BuildVisibleRegion(CLLocationCoordinate2D currentLocation)
		{
			var span = new MKCoordinateSpan(0.2,0.2);
			var region = new MKCoordinateRegion(currentLocation,span);

			return region;
		}
	}
}

This simple ViewController overrides the ViewDidLoad method, consumes the LocationService to get the current location and then displays that location on with a MKMapView. We build up the map view in two steps, the first creates the instance of the map view and sizes it to fit the viewable area of the given display. The MKMapView has a property that will automatically show an indicator of where the curent location is, setting this property is all you need to do to display the map and location. There is a catch though, if you were to display this map now you would see a map of the entire United States and not a reasonable local view of the area. The second step is what zooms the map into a reasonable region to display.

If we display this controller now in the iPhone Simulator, this is what we see.

Follow me on Mastodon!