How To Make an App Like Runkeeper: Part 1

Runkeeper, a GPS app like the one you’re about to make, has over 40 million users! This tutorial will show you how to make an app like Runkeeper. By Richard Critz.

Leave a rating/review
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

How About Some Breadcrumbs?

The post-run map is stunning, but how about having a map during the run?

The storyboard is set up using UIStackViews to make it easy to add one!

First, open NewRunViewController.swift and import MapKit:

import MapKit

Now, open Main.storyboard and find the New Run View Controller Scene. Be sure the Document Outline is visible. If not, press the button outlined in red below:

document outline

Drag a UIView into the Document Outline and place it between the Top Stack View and the Button Stack View. Make sure it appears between them and not inside one of them. Double-click it and rename it to Map Container View.

app like runkeeper - Add map container view

In the Attributes Inspector, check Hidden under Drawing.

set map container view hidden

In the Document Outline, Control-drag from the Map Container View to the Top Stack View and select Equal Widths from the pop-up.

Equal widths constraint

Drag an MKMapView into the Map Container View. Press the Add New Constraints button (A.K.A the "Tie Fighter button") and set all 4 constraints to 0. Make sure Constrain to margins is not checked. Click Add 4 Constraints.

add mapview constraints

With Map View selected in the Document Outline, open the Size Inspector (View\Utilities\Show Size Inspector). Double-click on the constraint Bottom Space to: Superview.

Bottom constraint

Change the priority to High (750).

priority 750

In the Document Outline, Control-drag from Map View to New Run View Controller and select delegate.

connect the delegate

Open the Assistant Editor, ensure it is showing NewRunViewController.swift and Control-drag from the Map View to create an outlet named mapView. Control-drag from Map Container View and create an outlet called mapContainerView.

connect map outlets

Close the Assistant Editor and open NewRunViewController.swift.

Add the following to the top of startRun():

mapContainerView.isHidden = false
mapView.removeOverlays(mapView.overlays)

To the top of stopRun() add the following:

mapContainerView.isHidden = true

Now, you need an MKMapViewDelegate to provide a renderer for the line. Add the following implementation in an extension at the bottom of the file:

extension NewRunViewController: MKMapViewDelegate {
  func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    guard let polyline = overlay as? MKPolyline else {
      return MKOverlayRenderer(overlay: overlay)
    }
    let renderer = MKPolylineRenderer(polyline: polyline)
    renderer.strokeColor = .blue
    renderer.lineWidth = 3
    return renderer
  }
}

This is just like the delegate you wrote in RunDetailsViewController.swift except that the line is blue.

Finally, you just need to add the line segment overlay and update the map region to keep it focused on the area of your run. Add the following to locationManager(_:didUpdateLocations:) after the line distance = distance + Measurement(value: delta, unit: UnitLength.meters):

let coordinates = [lastLocation.coordinate, newLocation.coordinate]
mapView.add(MKPolyline(coordinates: coordinates, count: 2))
let region = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 500, 500)
mapView.setRegion(region, animated: true)

Build and run and start a new run. You will see your new map updating in real time!

in-run map

Where To Go From Here?

Click here to download the the project up to this point.

You may have noticed that the user's pace always displays in "min/mi", even if your locale causes the distance to be displayed in meters (or km). Find a way to use the locale to choose between .minutesPerMile and .minutesPerKilometer in the places you call FormatDisplay.pace(distance:seconds:outputUnit:).

Continue to part two of the How to Make an App Like Runkeeper tutorial where you will introduce an achievement badge system.

As always, I look forward to your comments and questions! :]