แชร์ผ่าน


Summary of Chapter 28. Location and maps

Note

This book was published in the spring of 2016, and has not been updated since then. There is much in the book that remains valuable, but some of the material is outdated, and some topics are no longer entirely correct or complete.

Xamarin.Forms supports a Map element that derives from View. Because of the special platform requirements involved in using maps, they are implemented in a separate assembly, Xamarin.Forms.Maps, and involve a different namespace: Xamarin.Forms.Maps.

The geographic coordinate system

A geographic coordinate system identifies positions on a spherical (or nearly spherical) object like the Earth. A coordinate consists of both a latitude and longitude expressed in angles.

A great circle called the equator is midway between the two poles through which the Earth's axis conceptually extends.

Parallels and latitude

An angle measured north or south of the equator from the center of the Earth marks lines of equal latitude known as parallels. These range from 0 degrees at the equator to 90 degrees at the north and south poles. By convention, latitudes north of the equator are positive values, and those south of the equator are negative values.

Longitude and meridians

Halves of great circles from the north pole to the south pole are lines of equal longitude, also known as meridians. These are relative to the Prime Meridian in Greenwich, England. By convention, longitudes east of the Prime Meridian are positive values from 0 degrees to 180 degrees, and longitudes west of the Prime Meridian are negative values from 0 degrees to –180 degrees.

The equirectangular projection

Any flat map of the Earth introduces distortions. If all the lines of latitude and longitude are straight, and if equal differences in latitude and longitude angles correspond to equal distances on the map, the result is an equirectangular projection. This map distorts areas closer to the poles because they are horizontally stretched out.

The Mercator projection

The popular Mercator projection attempts to compensate for the horizontal stretching by also stretching these areas vertically. This results in a map where areas near the poles appear much larger than they really are, but any local area conforms quite closely with the actual area.

Map services and tiles

Map services use a variation of the Mercator projection called Web Mercator. The map services deliver bitmap tiles to a client based on location and zoom level.

Getting the user's location

The Xamarin.Forms Map classes do not include a facility to obtain the user's geographic location, but this is often desirable when working with maps, so a dependency service must handle it.

Note

Xamarin.Forms applications can instead use the Geolocation class included in Xamarin.Essentials.

The location tracker API

The Xamarin.FormsBook.Platform solution contains code for a location tracker API. The GeographicLocation structure encapsulates a latitude and longitude. The ILocationTracker interface defines two methods to start and pause the location tracker, and an event when a new location is available.

The iOS location manager

The iOS implementation of ILocationTracker is a LocationTracker class that makes use of the iOS CLLocationManager.

The Android location manager

The Android implementation of ILocationTracker is a LocationTracker class that makes use of the Android LocationManager class.

The UWP geo locator

The Universal Windows Platform implementation of ILocationTracker is a LocationTracker class that makes use of the UWP Geolocator.

Display the phone's location

The WhereAmI sample uses the location tracker to display the phone's location, both in text and on a equirectangular map.

The required overhead

Some overhead is required for WhereAmI to use the location tracker. First, all of the projects in the WhereAmI solution must have references to the corresponding projects in Xamarin.FormsBook.Platform, and each WhereAmI project must call the Toolkit.Init method.

Some additional platform-specific overhead, in the form of location permissions, is required.

Location permission for iOS

For iOS, the info.plist file must include items containing the text of a question asking the user to allow getting that user's location.

Location permissions for Android

Android applications that obtain the user's location must have an ACCESS_FILE_LOCATION permission in the AndroidManifest.xml file.

Location permissions for the UWP

A Universal Windows Platform application must have a location device capability marked in the Package.appxmanifest file.

Working with Xamarin.Forms.Maps

Several requirements are involved in using the Map class.

The NuGet package

The Xamarin.Forms.Maps NuGet library must be added to the application solution. The version number should be the same as the Xamarin.Forms package currently installed.

Initializing the Maps package

The application projects must call the Xamarin.FormsMaps.Init method after making a call to Xamarin.Forms.Forms.Init.

Enabling map services

Because the Map can obtain the user's location, the application must obtain permission for the user in the manner described earlier in this chapter:

Enabling iOS maps

An iOS application using Map needs two lines in the info.plist file.

Enabling Android maps

An authorization key is required for using Google Map services. This key is inserted in the AndroidManifest.xml file. In addition, the AndroidManifest.xml file requires manifest tags involved in obtaining the user's location.

Enabling UWP maps

A Universal Windows Platform application requires an authorization key for using Bing Maps. This key is passed as an argument to the Xamarin.FormsMaps.Init method. The application must also be enabled for location services.

The unadorned map

The MapDemos sample consists of a MapsDemoHomePage.xaml file and MapsDemoHomePage.xaml.cs code-behind file that allows navigating to various demonstration programs.

The BasicMapPage.xaml file shows how to display the Map view. By default it displays the city of Rome, but the map can be manipulated by the user.

To disable horizontal and vertical scrolling, set the HasScrollEnabled property to false. To disable zooming, set HasZoomEnabled to false. These properties might not work on all platforms.

Streets and Terrain

You can display different types of maps by setting the Map property MapType of type MapType, an enumeration with three members:

The MapTypesPage.xaml file shows how to use a radio button to select the map type. It makes use of the RadioButtonManager class in the Xamarin.FormsBook.Toolkit library and a class based on the MapTypeRadioButton.xaml file.

Map coordinates

A program can obtain the current area that the Map is displaying through the VisibleRegion property. This property is not backed by a bindable property, and there is no notification mechanism to indicate when it has changed, so a program that wishes to monitor the property should probably use a timer for that purpose.

VisibleRegion is of type MapSpan, a class with four read-only properties:

Position and Distance are both structures. Position defines two read-only properties set via the Position constructor:

Distance is intended to provide a unit-independent distance by converting between metric and English units. A Distance value can be created in several ways:

The value is available from three properties:

The MapCoordinatesPage.xaml file contains several Label elements for displaying the MapSpan information. The MapCoordinatesPage.xaml.cs code-behind file uses a timer to keep the information updated as the user manipulates the map.

Position extensions

A new library for this book named Xamarin.FormsBook.Toolkit.Maps contains map-specific but platform-independent types. The PositionExtensions class has a ToString method for Position, and a method to calculate the distance between two Position values.

Setting an initial location

You can call the MoveToRegion method of Map to programmatically set a location and zoom level on the map. The argument is of type MapSpan. You can create a MapSpan object using either of the following:

It's also possible to create a new MapSpan from an existing one using the methods ClampLatitude or WithZoom.

The WyomingPage.xaml file and WyomingPage.xaml.cs code-behind file demonstrates how to use the MoveToRegion method to display the state of Wyoming.

You can alternatively use the Map constructor with a MapSpan object to initialize the location of the map. The XamarinHQPage.xaml file shows how to do this entirely in XAML to display Xamarin's headquarters in San Francisco.

Dynamic zooming

You can use a Slider to dynamically zoom a map. The RadiusZoomPage.xaml file and RadiusZoomPage.xaml.cs code-behind file show how to change the radius of a map based on the Slider value.

The LongitudeZoomPage.xaml file and LongitudeZoomPage.xaml.cs code-behind file show an alternative approach that works better on Android, but neither approach works well on the Windows platforms.

The Phone's location

The IsShowingUser property of Map works a little differently on each platform as the ShowLocationPage.xaml file demonstrates:

  • On iOS, a blue dot indicates the phone's location but you must manually navigate there
  • On Android, an icon is displayed that when pushed moves the map to the phone's location
  • The UWP is similar to iOS but sometimes automatically navigates to the location

The MapDemos project attempts to mimic the Android approach by first defining an icon-based button based on the MyLocationButton.xaml file and MyLocationButton.xaml.cs code-behind file.

The GoToLocationPage.xaml file and GoToLocationPage.xaml.cs code-behind file use this button to navigate to the phone's location.

Pins and science museums

Finally, the Map class defines a Pins property of type IList<Pin>. The Pin class defines four properties:

  • Label of type string, a required property
  • Address of type string, an optional human-readable address
  • Position of type Position, indicating where the pin is displayed on the map
  • Type of type PinType, an enumeration, which is not used

The MapDemos project contains the file ScienceMuseums.xml, which lists science museums in the United States, and Locations and Site classes for deserializing this data.

The ScienceMuseumsPage.xaml file and ScienceMuseumsPage.xaml.cs code-behind file display pins for these science museums in the map. When the user taps a pin, it displays the address and a website for the museum.

The distance between two points

The PositionExtensions class contains a DistanceTo method with a simplified calculation of the distance between two geographic locations.

This is used in the LocalMuseumsPage.xaml file and LocalMuseumsPage.xaml.cs code-behind file to also display the distance to the museum from the user's location:

Triple screenshot of Local Museums Page

The program also demonstrates how to dynamically restrict the number of pins based on the location of the map.

Geocoding and back again

The Xamarin.Forms.Maps assembly also contains a Geocoder class with a GetPositionsForAddressAsync method that converts a text address into zero or more possible geographic positions, and another method GetAddressesForPositionAsync that converts in the other direction.

The GeocoderRoundTrip.xaml file and GeocoderRoundTrip.xaml.cs code-behind file demonstrate this facility.