środa, 22 marca 2017

Mapy i geolokalizacja w Xamarin.Forms

Hej,
w moim projekcie, zaraz na początkowym etapie miałem potrzebę użycia map. Dokładnie potrzebowałem poprosić użytkownika o wskazanie lokalizacji pasieki - w przyszłości mam zamiar wykorzystać te dane do pokazywania użytkownikowi z jednego z dostępnych API  pogody na pasiece i w pewnych przypadkach pokazywać mu notyfikacje (moja główna wartość biznesowa). Na start trafiłem na przygotowany przez ekipę Xamarina bibliotekę Xamarin.Forms.Maps, której użycie i konfiguracja opisana jest tutaj.
Niestety szybko okazało się, że funkcjonalność oferowana przez ten pakiet jest uboga i ogranicza się głównie do kontrolki mapy, na której możemy pokazać nieinteraktywnego pina. Szybko trafiłem na bibliotekę, która bazując na w/w bardzo rozszerza jej funkcjonalność, a którą bardzo polecam: TK.CustomMap - z jej pomocą możemy dodawać customowe, przeciągalne piny, rysować na mapie kształty, wyznaczać trasy itp. Instalacja z nugeta jest bezproblemowa i po konfiguracji opisanej np na githubie możemy zacząć dodawać mapy.

Na potrzeby testów i ewentualnej zmiany używanej biblioteki dodałem sobie interfejs:
public interface IMap
{
    void showMap();
    Task showMapForLocation(Action<string> onUserSelectPoint, double currentLat = 0, double currentLng = 0);
}

Pierwsza metoda służy mi do pokazania mapy - zapewne będę ją rozbudowywał o dodatkową funkcjonalność, jednak do zabawy z mapami po prostu pokazuje okienko z mapą. W samej aplikacji korzystam na razie tylko z drugiej funkcji i na jej przykładzie omówię moje użycie biblioteki - pełna implementacja jest wrzucona na githubie.
Na początek tworzę obiekt mojej mapy z początkową lokalizacją gdzieś w Polsce (52,20):
var map = new TK.CustomMap.TKCustomMap(MapSpan.FromCenterAndRadius(new Position(52, 20), Distance.FromKilometers(100)));

Utworzony obiekt dodaję do wcześniej przygotowanego widoku, a następnie tworzę obiekt pina,  dodaje go do mapy, a po kliknięciu w mapę, przesuwam pina w te miejsce.
var pin = new TK.CustomMap.TKCustomMapPin { Position = map.MapCenter, IsDraggable = true, ShowCallout = true, Title = "Lokalizacja pasieki" };
map.CustomPins = new List<TK.CustomMap.TKCustomMapPin> { pin };
map.MapClicked += (object sender, TK.CustomMap.TKGenericEventArgs<Position> e) =>
{
    pin.Position = e.Value;
};

W ten sposób, użytkownik może zarówno klikając w mapę jak i przeciągając pina po niej łatwo wskazać lokalizację. Teraz pozostaje nam temat drugi - czyli geolokalizacja. Na początek w celu ułatwienia użytkownikowi odnalezienia swojej pasieki staram się wycentrować mapę na jego bieżacej lokalizacji - użyłem do tego biblioteki Xam.Plugin.Geolocator - polecam
ją bo korzysta z async/await oraz sama pyta o przyznanie uprawnień w Androidzie 5.0+. Jej użycie sprowadza się tak naprawdę do paru linijek kodu:

if (Plugin.Geolocator.CrossGeolocator.Current.IsGeolocationAvailable && Plugin.Geolocator.CrossGeolocator.Current.IsGeolocationEnabled)
{
    userLocation = await Plugin.Geolocator.CrossGeolocator.Current.GetPositionAsync(10000);
    var userPosition = new Position(userLocation.Latitude, userLocation.Longitude);
    map.MoveToRegion(MapSpan.FromCenterAndRadius(userPosition, Distance.FromKilometers(3)));
    pin.Position = userPosition;
}

Jeżeli api geolokalizacji jest dostępne - pobieramy lokalizację z timeoutem 10s, zmieniamy strukturę lat/lng na tą z TK.CustomMaps i centrujemy mapę i pina. Na początek na moje potrzeby taka funkcjonalność jest wystarczająca chociaż będę musiał dodać jeszcze pole tekstowe do wyszukiwania adresu.  Dodanie obsługi map w aplikacji - korzystając z tutoriali i opisów z zamieszczonych tu linków nie nastręczyło mi większych trudności, a mam nadzieję że korzyść z tego płynąca będzie spora. Pozdrawiam i do następnego razu!


0 komentarze: