Tracking Highly Accurate Location in iOS — (Vol.4) Display location on the map

内容

In the last three Medium posts, I’ve explained how to get locations both in the foreground and background with the best accuracy. Before explaining much deeper location topics, I am going to take a time to implement map feature on the sample app.

It is because many location-related apps have a map. And even if your app doesn’t have a map, it often becomes necessary to have a map for debugging and tuning your location tracking feature.

First open Main.storyboard, and add MPMapView on the ViewController’s view

Enable Maps in the project’s Capabilities tab.

Implements MKMapViewDelegate protocol.

And add these member variables.

  • userAnnotationImage — Image of the user’s position annotation.
  • userAnnotationUserAnnotation object to indicate the user’s position. We subclass MKAnnotation and creates this UserAnnotation class for showing custom graphic (the red dot in the screenshot below) on the user’s position.
  • accuracyRangeCircle — MKOverlay class, the overlay showing current accuracy range of the location information (gray circle around the red dot)
    The wider the circle is the lower the accuracy is.
  • polyline- MKPolyline (subclass of MKOverlay) which shows the user’s path on the map (the blue path in the screenshot below.)
  • isZooming — State of zooming action
  • isBlockingAutoZoom — Flag meaning whether it is currently blocking auto zoom due to that the user is scrolling and interacting with the map.
  • zoomBlockingTimerTimer used to block auto zooming for 10 seconds after the user’s interaction to the map ends.
  • didInitialZoom — Boolean flag to store when the map have done initial zoom to the user’s location.

In viewDidLoad, we initialize some of these variables.

  • Set self as the delegate of mapView
  • Disable showsUserLocation of mapView because we use our own custom graphic for the indicator
  • Initialize the image of the user’s current location annotation
  • Set the accuracy range circle with initial dummy location and range width of 50 meters
  • add the accuracy range circle overlay to the map
  • Add an observer to monitor location update notification sent from LocationService class. updateMap method will be called every time new location is obtained.

Next we prepare this updateMap method**.**

This method calls two methods;

  • updatePolyline()
  • zoomTo(location: newLocation)

updatePolyline() draws the path that the user took by connecting all the tracked locations.

zoomTo() controls the zoom level and position of the map to make the current location of the user visible at the center of the map.

To generate a polyline, we first makes the array of CLLocationCoordinate2D objects from the locationDataArray in LocationService class. locationDataArray is the array storing all the tracked locations.

Then we passes this array to create a MKPolyline object.

zoomTo() is a little complicated.

  • Zoom if the map has never been zoomed to the position of the user’s location.
  • Move the map to the position of the user’s location if zoom is not disabled (i.e. isBlockingAutoZoom is false).
  • Add accuracyRangeCircle overlay — gray circle indicating the current GPS accuracy by the radius of the circle (smaller radius means better accuracy).
  • Add userAnnotation — the red dot indicator of the user’s current position

Zoom is disabled (i.e. isBlockingAutoZoom is set to true) when the user starts touching the map such as pinching or swiping the map. The app keeps isBlockingAutoZoom true for 10 seconds after the user’s last interaction to the map.By doing that, the app can avoid auto-focusing the map to the user’s latest location while the user is interacting with the map by himself.
This small trick gives much better UX to users especially if the app is running or navigation type of the app.

Override MKMapViewDelegate methods

Provide a renderer to draw an accuracy region and a polyline.

This delegate method provides one renderer object for drawing accuracyRangeCircle, and one renderer object for drawing the polyline.

Provide an annotation view object for the user’s current position annotation

Here you have to return MKAnnotationView object wrapping the annotation object. Since we added userAnnotation to mapView, it is that userAnnotation object which is passed in this function. We wrap this object in the annotationView object here.

React to the change of the map’s rendering region

This method will be called when the region of the map rendered on the screen is changed. This happens in these two cases

  • When a user pinches or scrolls the map
  • When the ViewController zooms the map by zoomTo() function.

We set isZooming flag to false when the user scrolls or pinches the map

We set isZooming flag to true when the ViewController zooms the map.

So, in case isZomming is false, it means the map has been moved by the user, thus we turn isBlockingAutoZoom to true to block the ViewController from doing any zoom. At the same time we start a timer of 10 seconds, and until this timer expires we keep this flag as true. After the 10 seconds, isBlockingAutoZoom is set to false, so the ViewController can zoom or move the map when new location is sent from the LocationService object.

We assume that when and slightly after the user has touched the map, he or she wants to look at the map for a while at that position and zoom level. Thus we block the map from any auto zoom. We assume that after 10 seconds, the user may be comfortable if the map resumes to move focus to the user’s latest location automatically each time new location of the user is obtained.

I’m running an app development studio in Tokyo called Goldrush Computing.
If you need any development force to empower your app with location tech magic, feel free to contact me any time.
[email protected]

总结
The article discusses implementing a map feature in a sample app before delving into deeper location topics. It guides on adding a map view, enabling maps in project settings, and initializing variables for user location annotation, accuracy range circle, and polyline. The 'updateMap' method is explained, which updates the map with the user's location and path. It includes controlling zoom levels and adding overlays for accuracy and user position. The article also covers how to handle zooming actions and interactions with the map to provide a better user experience. Additionally, it mentions overriding MKMapViewDelegate methods for rendering accuracy regions, polyline, and user annotations. The strategy of blocking auto zoom for a few seconds after user interaction with the map is highlighted to enhance user experience. The article concludes with a mention of the next post on filtering inaccurate locations and an offer for app development services from Goldrush Computing in Tokyo.