Wayfinding Instructions

iOS V4

In this tutorial we will show how to work with the route model returned from a directions service call. We will also show how you can utilize interaction between the route rendering on the map and textual instructions showed in another view.

See Wayfinding Translations, for examples of how to handle localization of routes and their presentation on the map.

In the route model there are some text properties that we will interpret as enum values, so start out by creating enums RouteContext describing whether we are outside or inside.

enum RouteContext : String
{
    case insideBuilding = "InsideBuilding"
    case outsideOnVenue = "OutsideOnVenue"
}

Create a subclass of UICollectionViewCell called RouteSegmentView

class RouteSegmentView : UITableViewCell {

Add a property called route that holds entire route model.

private var route: MPRoute?

Add a property called segment that holds the actual segment of route that this view is going to reflect.

private var segment:MPRouteSegmentPath = MPRouteSegmentPath()

Add a method called renderRouteInstructions that updates segment and route. Call the method updateViews when set.

func renderRouteInstructions(_ route:MPRoute, for segment:MPRouteSegmentPath) {
    self.route = route
    self.segment = segment
    updateViews()
}

Helper Methods

We will need some helper methods to make this example work. The helper methods will be added to our RouteSegmentView class. First create a method that can get us the previous step for later comparison.

Create a method getOutsideInsideInstructions that can get us instructions for walking inside or out of a building. This is determined by the routeContext property of an MPRouteStep

Create a method getElevationInstructions that can get us instructions for taking the stairs or elevator to another floor. This is determined by the highway and end_location.zLevel properties of a MPRouteStep.

Create a method getDefaultInstructions that can get us information about the default instructions in a route step. In some cases they are html formatted, so we need to pass it through an interpreter.

Create a method getDistanceInstructions that can get us information about the travelling distance. This is determined by the duration property of a MPRouteLeg. The distance is returned in meters so if you require imperial units, make a conversion.

Suggested Logic for Generating Meaningful Instructions

Obviously it is up to your application to present some instructions to the end user, but here a suggestion. Add a method called updateViews that will fire whenever our models change. Initialize an array of textual instructions and check for existence of a current leg.

We need a method to parse html because the directions instructions from Google contains html.

Create the Controller That Displays Generated Textual Instructions Segment by Segment

We use a collection view to do this but you can of course use whatever view that fits your use case best.

First we will define a protocol called RouteSegmentsControllerDelegate that will be used to handle the selection of each represented route segment. The method didSelectRouteSegment will be delegating the handling of route segment selections.

The Route Segments Controller

Create a controller class called RouteSegmentsController that inherits from UIViewController.

Add some properties to the controller

  • startingScrollingOffset We will do a side-ways scroll in the collection, so we will add a private point property to keep track of that

  • tableView the actual table view property.

  • delegate the delegate property.

The Route Segments Controller Data Source

Create an extension of RouteSegmentsController that implements UITableViewDataSource protocol.

Table View Delegate

Create an extension of RouteSegmentsController that implements UITableViewDelegate protocol. In method didSelectRowAtIndexPath update the current route segment.

Create a Controller That Renders a Map and Utilizes Interaction Between a Route Rendered on the Map and the Selected Instructions

Start by creating a controller class AdvancedDirectionsController that inherits from UIViewController, MPMapControlDelegate and MPDirectionsRendererDelegate.

Setup map-related member variables for AdvancedDirectionsController:

  • A UIView map property

  • A MapsIndoors MPMapControl property

  • A MapsIndoors MPDirectionsRenderer property

  • A stepWiseRenderer property used as a step-rendering property

Setup directions related member variables for AdvancedDirectionsController:

  • A routeVC property used as a child view controller to this VC

  • A heightConstraintForRouteView property that can control the visibility of the route view

  • A directionsVisible bool that can control the visibility of the route view by affecting the height of the route view

  • A searchButton that will open a search controller to choose your destination

  • A directions which is a MPMapsIndoors direction service. This will be initialized later.

  • A destinationLocation property

  • A originLocation witch will be as our origin location.

Create a setupMap method that sets up the UIView map and MapsIndoors Map Control object. To configure a mapConfig see Getting Started

Create a setupSearchButton method that sets up a button that can trigger the destination location selection.

Create a setupConstraints method that sets up all the layout constraints. In your projects you might do all this in a storyboard.

Create a setupRouteNav method that instantiates RouteSegmentsController and adds it as a child view controller. Assign this controller as its delegate.

Create a selectDestination method that instantiates and presents MySearchController. Assign this controller as its delegate.

Create a setupRenderer method that instantiates MPDirectionsRenderer and adds it as a child view controller. Assign this controller as its delegate.

Create a setOriginLocation method that mocks a origin location by searching for a random venue in MapsIndoors.

In the viewDidLoad put the pieces together by calling the above methods.

To handle the MPDirectionsRendererDelegate, use the onDirectionsRendererChangedFloor to listen to floor change:

Create a updateDirections method that sets up a MapsIndoors directions query. Execute a query and pass the resulting route object to the renderer.

Map Interactions

Let's do a couple of extensions for the map interactions. First implement the RouteSegmentsControllerDelegate through an extension. In didSelectRouteSegment update the leg index for the directions renderer.

Implement the MySearchControllerDelegate through an extension. In didSelectLocation update the destinationLocation property.

Last updated

Was this helpful?