Taoffi's blog

prisonniers du temps

Xamarin forms – what about maps?

Why do we use maps?

Apart from the pleasure (and poesy) of locating things in the global earth space, there is something practical and useful in using maps and geolocation.

I myself could never be able to live in big cities without mapping applications guiding me from a place to another and giving me such vital information like 'where can I park my car' (almost a dilemma in European cities at leastJ)

As we talk about maps, we of course talk about mobility (and vice versa). That puts it in a way where we might think that a mobile app is often linked to mapping features: if your app sells something (it often doesJ), the user will inevitably ask: where is it? How can I go there?... etc.

Xamarin forms maps package

The Xamarin forms maps package delivers a good solution to integrate maps into your XF applications.

A nice sample is delivered that explains how to get started with the package.

To avoid some of startup pitfalls, I compiled my own pitfalls and solutions here.

The package (Xamarin.Forms.Maps.dll) contains a few useful objects:

 

Xamarin.Forms.Maps - What / Who lives there?

The component exposes three main objects:

  • Map object (a View)
  • MapSpan object
  • Pin object (a BindableObject)

Finally an object: Geocoder for geocoding operations (that I didn't find really useful or simply operational)

More details and Inheritance

A Map (deriving from View) is of:

  • MapType (enumeration)
  • It has two MapSpan(s) representing the VisibleRegion and the LastMoveToRegion
  • And it contains a collection of Pin(s) (IList<Pin>)

A MapSpan is composed of its center (a Position: a structure of Latitude, Longitude), dimensions in terms of Distance (a structure with some factory methods (FromKilometers, FromMiles…) to apply values using known distance units).

The good news is that the Pin is a BindableObject. We will see how to use this to extend some features.

Extending Xamarin Forms Maps

You can simply use the maps package with its provided features and obtain good and useful results for your app's users: display pins on the map, when a pin is clicked, its label is displayed, and you can respond to that label's Tap event to open your selected item's specific form. That can be enough in many cases.

Other more demanding apps may need, for instance, to customize pin appearance and/or the callout for each pins… etc.

The standard Pin object is limited to handling objects' Address (string), Label (string), Position (coordinates) and pin Type (enumeration: Generic, Place, SavedPin or SearchResult). It also exposes a Clicked event to which your app can subscribe.

 

It does not handle other features that you may need… like specifying a pin icon, or a custom callout.

So, you think: still, we can derive a custom pin object that may provide such requested information.

Unfortunately that is not possible because Pin is a sealed class! (Why is it sealed?... mystery!. I hope the creators have good reason for this choice. For now, I find this a little strange)

Customizing maps: yet another solution

I found some interesting efforts to extend and circumvent the Xamarin maps limitations.

You may have a look at some Here… or Here.

Most efforts concentrate on offering Custom rendering solutions (For Droid and iOS. Few, if any, expose a Win Phone workable renderer).

The fact that we need a custom renderer for maps is inevitable if we opt to using the specific platform mapping features (which seems the reasonable choice). A structured (architectural) approach is required in any case.

What we want to handle in this sample, is a Place object:

It contains information about its location (latitude, longitude, address…) and other properties (Name, description, image…)

What we need in our current sample is:

  • Display a custom pushpin according to the type (category) of the Place at the pin location.
  • Display a custom callout when the pin would be clicked.
  • Raise a Clicked event when the callout would be tapped.

Instead of this:

We would like to have something like this :

As we cannot inherit the Pin class (sealed), let us create an iCustomPin class containing the target map Pin and providing the required customization features (here the pin's icon):

The iCustomPin class will act as a view model for the Pin, thus providing some (gets) of its properties: MapPinLabel, MapPinPosition, MapPinType… etc.

It exposes a DataObject (an 'object', which will contain a Place object in the current sample… Note: That may be refactored to a BindableProperty)

An iCustomMap object (deriving from the Xamarin forms Map) will be in charge of inserting / updating our custom pins. It may also provide a custom Callout control template (ContentView) that can be used for displaying the selected (Clicked) pushpin.

How these objects can be used?

The sample execution sequence can be as follows:

  • Data: create a list of sample places, each containing coordinates, description…
  • View: Insert a custom map control (iCustomMap object) into the page
  • For each ample place, add the corresponding custom pin (iCustomPin) to the custom map:
    • A custom pin contains a 'standard' Pin
    • Set standard Pin's BindingContext to the custom pin. (The custom pin contains the Data Object… which is the Place)
  • Rendering: the custom renderer, at each platform, can access the custom pin info (and thus the sample Place) through the Pin's BindingContext… It would then display the pushpins according to the specified icon asset, and eventually displays the place's callout when required.

 

 

 

In a following post, I will expose custom renderers details for Android and WP.

Will also try to polish the sample code a little more before publishing for download. Will keep you posted when readyJ

Comments are closed