MapKit in iOS

iOS 7 has brought a fresh new look to the entire UI, affecting also the Maps and the Map view. Let’s see what those changes are and how to take advantage of them.

If you check the Maps app, you will notice a slight update in the cartography of the map and hybrid mode. This update aims to deliver clearer cartographic information, so some graphic elements (the roads, for example) are blended to the map and labeling stands our more. Pins, callouts and user location views have been updated to embrace the new iOS 7 UI too. There is also the new tintColor property, which applied to MKMapView will affect down all the elements to show callouts and location views with matching colors.

iOS 7 has brought new ways you can look at the map: 3D mode. There is a new API to work with this 3D mode which is ON by default in iOS 7 and that allows you to offer the following new perspective:

Alt text

To control the 3D mode, open Xcode, create a Single View Application and add a MKMapView object in Interface Builder. Then, choose the Attributes Inspector and notice the checkmark on 3D Perspective. This property corresponds to the MKMapView property pitchEnabled, which can be set by code too.

Alt text

Continuous panning

There is another improvement that might seem trivial for many people, but this is actually a very nice new feature for those developers working with geographical areas close to longitude 180/-180 degrees. Before iOS 7, you could not enable panning across longitude 180/-180 degrees, so if you wanted to show places in the Indian Ocean, Japan and the US West Coast, for example, you had to do a lot of panning over Europe and Asia to reach both ends (the map ended on longitude 180 degrees on the right and on -180 degrees on the left side). Now, in iOS 7 you can span across meridian 180 and you can do infinite panning going all around the globe. You can also show the area containing annotations, which fall right and left from meridian 180/-180 very easily because all the calculations will be handled for you.

Annotations

Before iOS 7 you had to calculate the region with annotations having positive and negative coordinates, which led to errors. Now, you just pass an array containing the annotations you want to show using the method which sets the visible region so that the map displays them all:

3D Camera

A really cool feature is related to the 3D mode I mentioned above. You can now control and animate the user point of view (or camera) with respect to the map. In this way, you can position the camera anywhere in the 3D space. The MKMapCamera class allows you to define a camera object. To create the camera object you can use either the +camera or the + cameraLookingAtCenterCoordinate:fromEyeCoordinate:eyeAltitude: method. Once created, you can set its centerCoordinate, heading, pitch and altitude. The first property (centerCoordinate) is used to fix the latitude and longitude location of the camera on the map. The heading property sets the heading of the camera (measured in degrees) relative to true north. The pitch is instead the angle of the camera view, measured in degrees. A value of 0 results in a camera pointed straight down at the map. Angles greater than 0 result in a camera that is pitched toward the horizon by the specified number of degrees. The altitude property sets the altitude of the camera above the ground, measured in meters. Once you have created the camera and set its property you can assign the camera to the map view using the setCamera: method that is animatable.

To build an animation moving the camera in the 3D space, you need to create an array of cameras. Each camera has different settings and represents the animation steps. To start the animation, you set the map camera using the setMapCamera: method. You need to add this in an animation block. When the animation completes, the delegate method mapView:regionDidChangeAnimated: is fired. In that method, you grab a new camera from the camera arrays and set it to the map view. Let’s make an example.

Create a new Xcode project with a view controller. Name it MapAnimation and add a map view to the main view of the view controller. Set the view controller as the delegate of the map view object. Let’s create an instance variable in the implementation

In the viewDidLoad, we create the cameras (we are going to fly from the San Francisco Transamerica until the Rome Coliseum):

Now, add a button somewhere and create an action like this:

The goToNextCamera method is the important piece:

First, we check if the _camera contains objects. If not, we stop, otherwise we get the first object of the array (line 2) and we remove it from the array (line 3). Finally, we do the animation. Here, it is important to remember that you must not use the completion handler. Instead, you should implement the following delegate method:

There’s much more you can do. For example, you can flyover a point of interest or move the map in 3D showing buildings. Here, I just want to give a grasp of the new class.

Overlay Functionalities

iOS 7 introduces a new MKOverlayRenderer class that replaces MKOverlayView (now deprecated). The MKOverlayRenderer works as its predecessor MKOverlayView, which defines the basic behavior associated with all map-based overlays. Hierarchy and methods remain the same, so if you replace the name of the class, everything else should work pretty much the same way as it worked in the past.

There are also a few improvements introduced on MKTileOverlay. This class implements an overlay that is optimized for covering an area of the map using individual bitmap tiles. If you want to see some examples using and displaying tiles in your iOS projects, you can go to the Apple Map Overlay and Aerial Images post I wrote earlier this year. Essentially, you can use tile overlay objects to represent your own tile-based content and to coordinate the display of that content in a map view. Your tiles can supplement the underlying map content or replace it completely using the property canReplaceMapContent which represents wether the tile content fully covers the underlying map content or not.

There is also new constant to determine at which level you want to add the overlay object. Using addOverlay:level:, you can place the overlay either above roadways (using the MKOverlayLevelAboveRoads constant) or above map labels, shields, or POIs icons but below annotations and 3D projection buildings (using the MKOverlayLevelAboveLabels constant).

An additional new features is the possibility to draw geodesic polylines using the MKGeodesicPolyline class. A geodesic polyline is the line shape that represents the shortest path between a set of points over the Earth surface. Let’s see how this works. Using the project we created earlier, now create a MKMapView property and connect to the MKMapView object you already have. In the viewDidAppear method, create a structure containing the geographical coordinates of two locations, (i.e. San Francisco and New York in my case):

To create a geodesic polyline using the two locations, you can use the following method:

Then, add the geodesic polyline to the map:

Finally, add the following MKMapViewDelegate method to pass the MKPolylineRenderer to the map view. You can also define the stroke color, line width, and other line characteristics:

To make this work, don’t forget to set the delegate of the map view. In interface builder, connect the delegate outlet from the map view with the view controller. And that’s the result you should get:

Alt text

MKLocalSearch

MKLocalSearchRequest was introduced in iOS 6.1. It allows you to find a specific place by name, a list of places by type or addresses. Local search takes a freeform query string and returns a list of search results which are represented by MKMapItem containing coordinate and structured address and optionally a name, a phone number and a URL.

Let’s follow the steps to perform a search. First, create an instance of MKLocalSearchRequest:

Assign a natural language string with a searchable term. I’m using restaurant in this example:

Specify a map region to narrow the search results, defining the region center coordinate (I’m reusing sanFrancisco which I created previously) and the region span:

Initialize the search object MKLocalSearch:

Finally, perform the search:

response.mapItems returns an array of map items representing the search results. You can then add them as annotations to show them on the map.

MKDirections

The MKDirectionsRequest class is used by apps that work with turn-based directions. This class supports driving and walking directions, with alternate routes and time estimates, which by default are based on current traffic conditions. This API is not new, but there are a few new methods that have been added or updated with iOS 7. New in iOS 7 is the possibility to visualize turn-based directions directly in your app. Previously, Maps app was launched and the user was transferred there to visualize directions.

MKDirectionsRequest works in the same way as MKLocalSearchRequest, but let’s see the code together:

response.routes returns an array of route objects representing the directions between the start and end points. You can then show them on the map.

Final remarks

Although it might seem obvious, remember that directions and search are server based and thus, they require a network connection to operate. That’s something you should take into account when using those APIs to handle network problems correctly.

I hope you enjoyed going through the new features and updates in iOS 7 related to MapKit. If you are seeking to increase your understanding of the latest technologies and frameworks attend a comprehensive iOS training course with iNVASIVECODE.

Eva

iOS Consulting | INVASIVECODE

iOS Training | INVASIVECODE

(Visited 43 times, 1 visits today)