Zaawansowany Android w Kotlin 04.1: Mapy Google na Androida

1. Zanim zaczniesz

Tworzenie aplikacji przy użyciu Map Google umożliwia dodawanie do aplikacji nowych funkcji, takich jak zdjęcia satelitarne, zaawansowane elementy interfejsu do map, śledzenie lokalizacji oraz znaczniki lokalizacji. Możesz zwiększyć wartość standardowych Map Google, pokazując informacje z własnego zbioru danych, takie jak lokalizacje znanych miejsc do wędkowania czy wspinaczki. Możesz też tworzyć gry, w których gracz eksploruje świat fizyczny, np. podczas poszukiwania skarbów, a nawet w grach w rzeczywistości rozszerzonej.

W ramach tej lekcji tworzysz aplikację Mapy Google o nazwie Wander, która wyświetla dostosowane mapy i pokazuje lokalizację użytkownika.

Wymagania wstępne

Wiedza na temat następujących zagadnień:

  • Jak utworzyć podstawową aplikację na Androida i uruchomić ją w Android Studio.
  • Jak tworzyć zasoby, takie jak ciągi znaków, i nimi zarządzać.
  • Jak refaktoryzować kod i zmieniać nazwy zmiennych w Android Studio.
  • Jak korzystać z Map Google jako użytkownik.
  • Jak ustawić uprawnienia w czasie działania.

Czego się nauczysz

  • Jak uzyskać klucz interfejsu API z Konsoli interfejsów API Google i zarejestrować go w aplikacji
  • Jak zintegrować Mapę Google z aplikacją
  • Jak wyświetlać różne typy map
  • Określanie stylu mapy Google
  • Jak dodać znaczniki do mapy
  • Jak umożliwić użytkownikowi umieszczanie znacznika w ciekawym miejscu
  • Jak włączyć śledzenie lokalizacji
  • Jak utworzyć aplikację Wander z umieszczoną Mapą Google
  • Jak tworzyć niestandardowe funkcje aplikacji, takie jak znaczniki i styl
  • Jak włączyć śledzenie lokalizacji w aplikacji

2. Aplikacje ogółem

W ramach tego ćwiczenia w Codelabs tworzysz aplikację Wander, która wyświetla mapę Google o niestandardowym stylu. Aplikacja Wander pozwala umieszczać znaczniki w lokalizacjach, dodawać nakładki i obserwować lokalizację w czasie rzeczywistym.

5b12eda7f467bc2f.png

3. Zadanie: skonfiguruj projekt i uzyskaj klucz interfejsu API

Pakiet Maps SDK na Androida wymaga klucza interfejsu API. Aby uzyskać klucz interfejsu API, zarejestruj swój projekt w interfejsie API Strona Usługi. Klucz interfejsu API jest powiązany z certyfikatem cyfrowym, który łączy aplikację z jej autorem. Więcej informacji o używaniu certyfikatów cyfrowych i podpisywaniu aplikacji znajdziesz w artykule Podpisywanie aplikacji.

W ramach tego ćwiczenia w Codelabs użyjesz klucza interfejsu API na potrzeby certyfikatu debugowania. Certyfikat debugowania jest z założenia niezabezpieczony, zgodnie z opisem w artykule Podpisywanie kompilacji do debugowania. Opublikowane aplikacje na Androida, które używają pakietu SDK Map Google na Androida, wymagają drugiego klucza interfejsu API – klucza certyfikatu wersji. Więcej informacji o uzyskiwaniu certyfikatu wersji znajdziesz w artykule na temat uzyskiwania klucza interfejsu API.

Android Studio zawiera szablon aktywności w Mapach Google, który generuje przydatny kod szablonu. Kod szablonu zawiera plik google_maps_api.xml zawierający link, który ułatwia uzyskanie klucza interfejsu API.

Krok 1. Utwórz projekt Wander z użyciem szablonu Map

  1. Utwórz nowy projekt w Android Studio.
  2. Wybierz szablon Aktywność w Mapach Google.

d6b874bb19ea68cd.png

  1. Nazwij projekt Wander.
  2. Ustaw minimalny poziom interfejsu API na API 19. Wybierz język Kotlin.
  3. Kliknij Zakończ.
  4. Gdy aplikacja zostanie skompilowana, spójrz na swój projekt i powiązane z mapami te pliki, które Android Studio dla Ciebie tworzy:

google_maps_api.xml – używasz tego pliku konfiguracji do przechowywania klucza interfejsu API. Szablon wygeneruje dwa pliki google_maps_api.xml: jeden do debugowania i jeden do wersji. Plik klucza interfejsu API certyfikatu debugowania znajduje się w lokalizacji src/debug/res/values. Plik klucza interfejsu API certyfikatu wersji znajduje się w lokalizacji src/release/res/values. W ramach tego ćwiczenia w Codelabs używasz tylko certyfikatu debugowania.

activity_maps.xml – plik układu zawiera pojedynczy fragment na całym ekranie. Klasa SupportMapFragment jest podklasą klasy Fragment. SupportMapFragment to najprostszy sposób na umieszczenie mapy w aplikacji. To otoka wokół widoku mapy, która automatycznie zaspokaja niezbędne potrzeby związane z cyklem życia.

Możesz uwzględnić SupportMapFragment w pliku układu, używając tagu <fragment> w dowolnym ViewGroup, z dodatkowym atrybutem name.

android:name="com.google.android.gms.maps.SupportMapFragment"

MapsActivity.java – plik MapsActivity.java tworzy instancję SupportMapFragment w metodzie onCreate() i używa klasy getMapAsync(), aby automatycznie zainicjować system map i widok. Działanie zawierające SupportMapFragment musi implementować interfejs OnMapReadyCallback i metodę onMapReady() tego interfejsu. Metoda onMapReady() jest wywoływana po wczytaniu mapy.

Krok 2. Uzyskaj klucz interfejsu API

  1. Otwórz wersję do debugowania pliku google_maps_api.xml.
  2. Odszukaj w pliku komentarz z długim adresem URL. Parametry adresu URL zawierają konkretne informacje o aplikacji.
  3. Skopiuj URL i wklej go w przeglądarce.
  4. Postępuj zgodnie z instrukcjami, aby utworzyć projekt na stronie Interfejsy API Strona Usługi. Dzięki parametrom w podanym adresie URL strona wie, że ma automatycznie włączyć pakiet Maps SDK na Androida.
  5. Kliknij Utwórz klucz interfejsu API.
  6. Na następnej stronie przejdź do sekcji Klucze interfejsu API i kliknij utworzony przed chwilą klucz.
  7. Kliknij Ogranicz klucz i wybierz Maps SDK na Androida, by ograniczyć użycie klucza do aplikacji na Androida.
  8. Skopiuj wygenerowany klucz interfejsu API. Zaczyna się od „AIza"”.
  9. W pliku google_maps_api.xml wklej klucz do ciągu znaków google_maps_key w miejscu, w którym znajduje się ciąg YOUR_KEY_HERE.
  10. Uruchom aplikację. W swojej aktywności powinna wyświetlić się mapa ze znacznikiem ustawionym w Sydney w Australii. (Znacznik Sydney jest częścią szablonu i możesz go później zmienić).

34dc9dd877c90996.png

Krok 3. Zmień nazwę aplikacji mMap

MapsActivity ma prywatny element lateinit var o nazwie mMap, który jest typu GoogleMap. Aby zachować zgodność z konwencjami nazewnictwa Kotlin, zmień nazwę mMap na map.

  1. W MapsActivity kliknij prawym przyciskiem myszy mMap i wybierz Refaktoryzacja > Zmień nazwę...

e713ccb3384450c6.png

  1. Zmień nazwę zmiennej na map.

Zwróć uwagę, że wszystkie odwołania do mMap w funkcji onMapReady() zmieniają się też na map.

4. Zadanie: dodaj typy map

W Mapach Google dostępnych jest kilka typów map: zwykłe, hybrydowe, satelitarne, terenowe i „brak” (brak mapy).

Normalna mapa

Mapa satelitarna

Mapa hybrydowa

Mapa terenu

Każdy typ mapy dostarcza innych rodzajów informacji. Na przykład podczas używania map do nawigacji w samochodzie warto sprawdzić nazwy ulic, aby skorzystać z standardowej opcji. Podczas wędrówki mapa ukształtowania terenu może pomóc w określeniu, ile jeszcze musisz się pokonać, aby dostać się na szczyt.

W tym zadaniu:

  1. Dodaj pasek aplikacji z menu opcji, które umożliwia użytkownikowi zmianę typu mapy.
  2. Przesuń lokalizację początkową mapy do swojej lokalizacji domowej.
  3. Dodano obsługę znaczników, które wskazują pojedyncze lokalizacje na mapie i mogą zawierać etykiety.

Menu dodawania typów map

W tym kroku dodasz pasek aplikacji z menu opcji, które umożliwia użytkownikowi zmianę typu mapy.

  1. Aby utworzyć nowy plik XML menu, kliknij prawym przyciskiem myszy katalog res i wybierz New (Nowy) > Plik zasobów Androida.
  2. W oknie nadaj plikowi nazwę map_options.
  3. Jako typ zasobu wybierz Menu.
  4. Kliknij OK.
  5. Na karcie Kod zastąp kod w nowym pliku poniższym kodem, aby utworzyć opcje menu mapy. Wartość „brak” typ mapy jest pomijany, ponieważ „none” (brak) spowoduje w ogóle brak mapy. Ten krok powoduje błąd, ale zostanie on rozwiązany w następnym kroku.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
       android:id="@+id/normal_map"
       android:title="@string/normal_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/hybrid_map"
       android:title="@string/hybrid_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/satellite_map"
       android:title="@string/satellite_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/terrain_map"
       android:title="@string/terrain_map"
       app:showAsAction="never" />
</menu>
  1. W programie strings.xml dodaj zasoby dla atrybutów title, aby naprawić błędy.
<resources>
   ...
   <string name="normal_map">Normal Map</string>
   <string name="hybrid_map">Hybrid Map</string>
   <string name="satellite_map">Satellite Map</string>
   <string name="terrain_map">Terrain Map</string>
   <string name="lat_long_snippet">Lat: %1$.5f, Long: %2$.5f</string>
   <string name="dropped_pin">Dropped Pin</string>
   <string name="poi">poi</string>
</resources>
  1. W MapsActivity zastąp metodę onCreateOptionsMenu() i powiększ menu z pliku zasobów map_options.
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
   val inflater = menuInflater
   inflater.inflate(R.menu.map_options, menu)
   return true
}
  1. W MapsActivity.kt zastąp metodę onOptionsItemSelected(). Zmień typ mapy za pomocą stałych typu mapy, aby odzwierciedlić wybór użytkownika.
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
   // Change the map type based on the user's selection.
   R.id.normal_map -> {
       map.mapType = GoogleMap.MAP_TYPE_NORMAL
       true
   }
   R.id.hybrid_map -> {
       map.mapType = GoogleMap.MAP_TYPE_HYBRID
       true
   }
   R.id.satellite_map -> {
       map.mapType = GoogleMap.MAP_TYPE_SATELLITE
       true
   }
   R.id.terrain_map -> {
       map.mapType = GoogleMap.MAP_TYPE_TERRAIN
       true
   }
   else -> super.onOptionsItemSelected(item)
}
  1. Uruchom aplikację.
  2. Kliknij 428da163b831115b.png, aby zmienić typ mapy. Zwróć uwagę, jak wygląd mapy zmienia się w poszczególnych trybach.

6fa42970d87f5dc7.png

5. Zadanie: dodaj znaczniki

Domyślnie wywołanie zwrotne onMapReady() zawiera kod, który umieszcza znacznik w Sydney w Australii, gdzie utworzono Mapy Google. Domyślne wywołanie zwrotne również animuje mapę, aby przesunąć ją do Sydney.

W tym zadaniu kamera na mapie przesuwa się do Twojego domu, powiększasz do wybranego poziomu i umieszczasz tam znacznik.

Krok 1. Powiększ widok domu i dodaj znacznik

  1. W pliku MapsActivity.kt znajdź metodę onMapReady(). Usuń z niego kod, który umieszcza znacznik w Sydney i przesuwa kamerę. Tak powinna teraz wyglądać Twoja metoda.
override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

}
  1. Wykonaj te instrukcje, aby sprawdzić szerokość i długość geograficzną swojego domu.
  2. Utwórz wartość szerokości i długości geograficznej i wpisz ich wartości zmiennoprzecinkowe.
val latitude = 37.422160
val longitude = -122.084270
  1. Utwórz nowy obiekt LatLng o nazwie homeLatLng. W obiekcie homeLatLng przekaż utworzone przed chwilą wartości.
val homeLatLng = LatLng(latitude, longitude)
  1. Utwórz val, aby określić, jak powiększony chcesz być na mapie. Użyj poziomu powiększenia 15f.
val zoomLevel = 15f

Poziom powiększenia steruje powiększeniem mapy. Oto lista pokazująca poziom szczegółowości poszczególnych poziomów powiększenia:

  • 1: świat
  • 5: ląd/kontynent
  • 10: miasto
  • 15: ulice
  • 20: budynki
  1. Przesuń kamerę do homeLatLng, wywołując funkcję moveCamera() w obiekcie map i przekazując obiekt CameraUpdate za pomocą CameraUpdateFactory.newLatLngZoom(). Przekaż obiekt homeLatLng i zoomLevel.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
  1. Dodaj znacznik do mapy w miejscu homeLatLng.
map.addMarker(MarkerOptions().position(homeLatLng))

Ostateczna metoda powinna wyglądać tak:

override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

   //These coordinates represent the latitude and longitude of the Googleplex.
   val latitude = 37.422160
   val longitude = -122.084270
   val zoomLevel = 15f

   val homeLatLng = LatLng(latitude, longitude)
   map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
   map.addMarker(MarkerOptions().position(homeLatLng))
}
  1. Uruchom aplikację. Mapa powinna przesunąć się na Twój dom, powiększyć do wybranego poziomu i umieścić znacznik na Twoim domu.

fc939024778ee76.png

Krok 2. Zezwól użytkownikom na dodawanie znacznika przez długie kliknięcie

W tym kroku dodajesz znacznik, gdy użytkownik dotknie i przytrzyma lokalizację na mapie.

  1. Utwórz w regionie MapsActivity pośrednik metody o nazwie setMapLongClick(), który przyjmuje GoogleMap jako argument.
  2. Dołącz detektor setOnMapLongClickListener do obiektu mapy.
private fun setMapLongClick(map:GoogleMap) {
   map.setOnMapLongClickListener { }
}
  1. W setOnMapLongClickListener() wywołaj metodę addMarker(). Przekaż nowy obiekt MarkerOptions z wartością przekazaną LatLng.
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. Na końcu metody onMapReady() wywołaj setMapLongClick() za pomocą map.
override fun onMapReady(googleMap: GoogleMap) {
   ...
  
   setMapLongClick(map)
}
  1. Uruchom aplikację.
  2. Naciśnij i przytrzymaj mapę, by umieścić znacznik w wybranej lokalizacji.
  3. Kliknij znacznik, który będzie wyśrodkowany na ekranie.

4ff8d1c1db3bca9e.png

Krok 3. Dodaj okno informacyjne dla znacznika

W tym kroku dodajesz element InfoWindow, który wyświetla współrzędne znacznika po jego kliknięciu.

  1. W setMapLongClick()setOnMapLongClickListener() utwórz val dla usługi snippet. Krótki opis to dodatkowy tekst wyświetlany po tytule. Fragment kodu zawiera szerokość i długość geograficzną znacznika.
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A snippet is additional text that's displayed after the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. W narzędziu addMarker() ustaw title znacznika na „Dorpped Pin” za pomocą zasobu ciągu tekstowego R.string.dropped_pin.
  2. Ustaw snippet znacznika na snippet.

Ukończona funkcja wygląda tak:

private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A Snippet is Additional text that's displayed below the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
               .title(getString(R.string.dropped_pin))
               .snippet(snippet)
              
       )
   }
}
  1. Uruchom aplikację.
  2. Naciśnij i przytrzymaj mapę, aby upuścić znacznik lokalizacji.
  3. Dotknij znacznika, aby wyświetlić okno informacyjne.

63f210e6e47dfa29.png

Krok 4. Dodaj detektor ciekawych miejsc

Domyślnie ciekawe miejsca (POI) są wyświetlane na mapie wraz z odpowiednimi ikonami. Ciekawe miejsca to między innymi parki, szkoły i budynki urzędowe. Jeśli typ mapy jest ustawiony na normal, na mapie pojawiają się też ciekawe miejsca firm. Ciekawe miejsca dla firm to firmy, takie jak sklepy, restauracje i hotele.

W tym kroku dodasz do mapy obiekt GoogleMap.OnPoiClickListener. Ten detektor kliknięć umieszcza znacznik na mapie natychmiast po kliknięciu przez użytkownika ciekawego miejsca. Detektor kliknięć wyświetla też okno informacyjne zawierające nazwę ciekawego miejsca.

  1. Utwórz w regionie MapsActivity pośrednik metody o nazwie setPoiClick(), który przyjmuje GoogleMap jako argument.
  2. W metodzie setPoiClick() ustaw wartość OnPoiClickListener w przekazywanych GoogleMap.
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->

   }
}
  1. W setOnPoiClickListener() utwórz val poiMarker dla znacznika .
  2. Ustaw znacznik jako znacznik, używając opcji map.addMarker(), przy czym MarkerOptions wskazuje nazwę ciekawego miejsca (title).
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
   }
}
  1. W funkcji setOnPoiClickListener() wywołaj showInfoWindow() w poiMarker, aby natychmiast wyświetlić okno informacyjne.
poiMarker.showInfoWindow()

Końcowy kod funkcji setPoiClick() powinien wyglądać tak.

private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
       poiMarker.showInfoWindow()
   }
}
  1. Na końcu onMapReady() zadzwoń pod numer setPoiClick() i przekaż: map.
override fun onMapReady(googleMap: GoogleMap) {
   ...

   setPoiClick(map)
}
  1. Uruchom aplikację i znajdź ciekawe miejsce, np. park lub kawiarnię.
  2. Kliknij ciekawe miejsce, aby umieścić na nim znacznik i wyświetlić jego nazwę w oknie informacyjnym.

f4b0972c75d5fa5f.png

6. Zadanie: określ styl mapy

Mapy Google możesz dostosowywać na wiele sposobów, nadając im niepowtarzalny wygląd.

Obiekt MapFragment możesz dostosować, korzystając z dostępnych atrybutów XML, tak jak w przypadku innych fragmentów. W tym kroku możesz jednak dostosować wygląd i styl zawartości obiektu MapFragment, używając metod obiektu GoogleMap.

Aby utworzyć niestandardowy styl mapy, musisz wygenerować plik JSON określający sposób wyświetlania obiektów na mapie. Nie musisz tworzyć tego pliku JSON ręcznie. Google udostępnia kreator stylu Maps Platform, który generuje plik JSON po wybraniu stylu graficznego mapy. W tym zadaniu nadasz styl mapie na motyw retro, co oznacza, że mapa będzie w starych kolorach i dodasz kolorowe drogi.

Krok 1. Utwórz styl mapy

  1. Otwórz w przeglądarce stronę https://mapstyle.withgoogle.com/.
  2. Wybierz Utwórz styl.
  3. Wybierz Retro.

208b3d3aeab0d9b6.png

  1. Kliknij Więcej opcji.

4a35faaf9535ee82.png

  1. Wybierz Droga > Wypełnij.
  2. Zmień kolor dróg na dowolny wybrany kolor (np. różowy).

92c3293749293a4c.png

  1. Kliknij Zakończ.

f1bfe8585eb69480.png

  1. Skopiuj kod JSON z wyświetlonego okna i w razie potrzeby schowaj go w notatce zwykłego tekstu do wykorzystania w następnym kroku.

3c32168b299d6420.png

Krok 2. Dodaj styl do mapy

  1. W Android Studio w katalogu res utwórz katalog zasobów i nadaj mu nazwę raw. Korzystasz z zasobów katalogu raw takich jak kod JSON.
  2. Utwórz w usłudze res/raw plik o nazwie map_style.json.
  3. Wklej kod JSON dodany do schowka do nowego pliku zasobów.
  4. W narzędziu MapsActivity utwórz zmienną klasy TAG nad metodą onCreate(). Służy do logowania.
private val TAG = MapsActivity::class.java.simpleName
  1. W funkcji MapsActivity utwórz też funkcję setMapStyle(), która pobiera GoogleMap.
  2. W setMapStyle() dodaj blok try{}.
  3. W bloku try{} utwórz val success dla powodzenia stylu. Dodajesz następujący blok typu „catch” (następujący).
  4. W bloku try{} ustaw styl JSON na mapę, wywołaj setMapStyle() w obiekcie GoogleMap. Przekazuj obiekt MapStyleOptions, który wczytuje plik JSON.
  5. Przypisz wynik użytkownikowi success. Metoda setMapStyle() zwraca wartość logiczną wskazującą stan analizy pliku stylu i ustalenie stylu.
private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )
   }
}
  1. Dodaj instrukcję if dla argumentu success za fałsz. Jeśli stylizacja się nie uda, wydrukuj dziennik informujący o niepowodzeniu analizy.
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   }
}
  1. Dodaj blok catch{}, aby obsłużyć brakujący plik stylu. Jeśli nie można wczytać pliku, w bloku catch zgłoś Resources.NotFoundException.
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}

Gotowa metoda powinna wyglądać tak:

private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )

       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}
  1. Na koniec wywołaj metodę setMapStyle() w metodzie onMapReady() przekazywanej w obiekcie GoogleMap.
override fun onMapReady(googleMap: GoogleMap) {
   ...
   setMapStyle(map)
}
  1. Uruchom aplikację.
  2. Ustaw mapę na tryb normal, a nowy styl powinien być widoczny z motywami w stylu retro i drogami w wybranym kolorze.

b59d6cb81f02a14f.png

Krok 3. Nadaj styl znacznikowi

Możesz jeszcze bardziej spersonalizować mapę, określając styl znaczników. W tym kroku zmienisz domyślne czerwone znaczniki w coś bardziej atrakcyjnego.

  1. W metodzie onMapLongClick() dodaj poniższy wiersz kodu do obiektu MarkerOptions() konstruktora, aby użyć znacznika domyślnego, ale zmienić jego kolor na niebieski.
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))

Teraz onMapLongClickListener() wygląda tak:

map.setOnMapLongClickListener { latLng ->
   // A snippet is additional text that's displayed after the title.
   val snippet = String.format(
       Locale.getDefault(),
       "Lat: %1$.5f, Long: %2$.5f",
       latLng.latitude,
       latLng.longitude
   )
   map.addMarker(
       MarkerOptions()
           .position(latLng)
           .title(getString(R.string.dropped_pin))
           .snippet(snippet)
         .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
   )
}
  1. Uruchom aplikację. Znaczniki, które pojawiają się po długim kliknięciu, mają teraz odcień niebieski. Zwróć uwagę, że znaczniki ciekawych miejsc są nadal czerwone, ponieważ nie dodano stylu do metody onPoiClick().

b9916bca3c367e3.png

7. Zadanie: dodawanie nakładki

Jednym ze sposobów dostosowywania mapy Google jest rysowanie na niej. Ta technika jest przydatna, jeśli chcesz wyróżnić konkretny rodzaj lokalizacji, np. popularne łowiska.

  • Kształty: do mapy możesz dodawać linie łamane, wielokąty i okręgi.
  • GroundOverlay obiekty: nakładka na ziemi to obraz na stałe umieszczony na mapie. W przeciwieństwie do znaczników nakładki na powierzchni są zorientowane na powierzchnię Ziemi, a nie na ekran. Obracanie, przechylanie lub powiększanie mapy powoduje zmianę orientacji obrazu. Nakładki na powierzchni są przydatne, gdy chcesz poprawić pojedynczy obraz w jednym obszarze mapy.

Krok: dodaj nakładkę z powierzchnią

W tym zadaniu dodajesz do lokalizacji domu nakładkę na ziemi w kształcie Androida.

  1. Pobierz ten obraz Androida i zapisz go w folderze res/drawable. Sprawdź, czy nazwa pliku to android.png.

61fabd56a0841b44.png

  1. W usłudze onMapReady() po wywołaniu przeniesienia kamery do pozycji domu utwórz obiekt GroundOverlayOptions.
  2. Przypisanie obiektu do zmiennej o nazwie androidOverlay.
val androidOverlay = GroundOverlayOptions()
  1. Użyj metody BitmapDescriptorFactory.fromResource(), aby utworzyć obiekt BitmapDescriptor na podstawie pobranego zasobu obrazu.
  2. Przekaż utworzony obiekt BitmapDescriptor do metody image() obiektu GroundOverlayOptions.
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
  1. Utwórz float overlaySize dla szerokości wybranej nakładki (w metrach). W tym przykładzie dobrze sprawdza się szerokość 100f.

Ustaw właściwość position dla obiektu GroundOverlayOptions, wywołując metodę position() i przekazując obiekt homeLatLng oraz overlaySize.

val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
   .position(homeLatLng, overlaySize)
  1. Wywołaj funkcję addGroundOverlay() w obiekcie GoogleMap i przekaż obiekt GroundOverlayOptions.
map.addGroundOverlay(androidOverlay)
  1. Uruchom aplikację.
  2. Zmień wartość zoomLevel na 18f, aby widzieć obraz Androida jako nakładkę.

b1b25b0acd6a9807.png

8. Zadanie: włącz śledzenie lokalizacji

Użytkownicy często używają Map Google, aby sprawdzić swoją aktualną lokalizację. Aby wyświetlić lokalizację urządzenia na mapie, możesz użyć warstwy danych o lokalizacji.

Warstwa danych o lokalizacji dodaje do mapy ikonę Moja lokalizacja.

f317f84dcb3ac3a1.png

Gdy użytkownik kliknie przycisk, mapa zostanie wyśrodkowana na lokalizacji urządzenia. Lokalizacja jest wyświetlana jako niebieska kropka, jeśli urządzenie jest nieruchome, oraz niebieska szewron, gdy urządzenie jest w ruchu.

W tym zadaniu włączysz warstwę danych o lokalizacji.

Krok: poproś o dostęp do lokalizacji

Aby włączyć śledzenie lokalizacji w Mapach Google, wystarczy wpisać jeden wiersz kodu. Musisz jednak upewnić się, że użytkownik przyznał dostęp do lokalizacji (korzystając z modelu uprawnień czasu działania).

W tym kroku prosisz o dostęp do lokalizacji i włączysz śledzenie lokalizacji.

  1. Sprawdź, czy w pliku AndroidManifest.xml znajduje się uprawnienie FINE_LOCATION. Android Studio wstawił to uprawnienie podczas wybierania szablonu Map Google.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. W MapsActivity utwórz zmienną klasy REQUEST_LOCATION_PERMISSION.
private val REQUEST_LOCATION_PERMISSION = 1
  1. Aby sprawdzić, czy przyznano uprawnienia, utwórz w MapsActivity metodę o nazwie isPermissionGranted(). W przypadku tej metody sprawdź, czy użytkownik przyznał Ci odpowiednie uprawnienia.
private fun isPermissionGranted() : Boolean {
  return ContextCompat.checkSelfPermission(
       this,
      Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
  1. Aby włączyć śledzenie lokalizacji w swojej aplikacji, utwórz w narzędziu MapsActivity metodę o nazwie enableMyLocation(), która nie przyjmuje żadnych argumentów i nie zwraca niczego. Sprawdź w środku uprawnienia ACCESS_FINE_LOCATION. Po przyznaniu uprawnień włącz warstwę lokalizacji. W przeciwnym razie poproś o odpowiednie uprawnienia.
private fun enableMyLocation() {
   if (isPermissionGranted()) {
       map.isMyLocationEnabled = true 
   }
   else {
       ActivityCompat.requestPermissions(
           this,
           arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
           REQUEST_LOCATION_PERMISSION
       )
   }
}
  1. Wywołaj funkcję enableMyLocation() z wywołania zwrotnego onMapReady(), aby włączyć warstwę lokalizacji.
override fun onMapReady(googleMap: GoogleMap) {
   ...
   enableMyLocation()
}
  1. Zastąp metodę onRequestPermissionsResult(). Sprawdź, czy requestCode jest równa REQUEST_LOCATION_PERMISSION. Jeśli tak, oznacza to, że uprawnienia zostały przyznane. Jeśli to uprawnienie zostało przyznane, sprawdź też, czy tablica grantResults zawiera w pierwszym boksie pole PackageManager.PERMISSION_GRANTED. Jeśli tak, wywołaj enableMyLocation().
override fun onRequestPermissionsResult(
   requestCode: Int,
   permissions: Array<String>,
   grantResults: IntArray) {
   if (requestCode == REQUEST_LOCATION_PERMISSION) {
       if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
           enableMyLocation()
       }
   }
}
  1. Uruchom aplikację. Powinno pojawić się okno z prośbą o dostęp do lokalizacji urządzenia. Przyznaj uprawnienia.

da7e23e00ec762c1.png

Aktualna lokalizacja urządzenia na mapie jest oznaczona niebieską kropką. Zwróć uwagę na przycisk lokalizacji. Jeśli przesuniesz mapę poza swoją lokalizację i klikniesz ten przycisk, mapa zostanie wyśrodkowana na lokalizacji urządzenia.

5b12eda7f467bc2f.png

9. Kod rozwiązania

Pobierz kod ukończenia ćwiczenia z programowania.

$  git clone https://github.com/googlecodelabs/android-kotlin-geo-maps

Możesz też pobrać repozytorium jako plik ZIP, rozpakować je i otworzyć w Android Studio.

10. Podsumowanie

Gratulacje! Dodałeś(-aś) mapę Google do aplikacji Kotlin na Androida i nadałeś jej styl.

11. Więcej informacji

Dokumentacja dla deweloperów aplikacji na Androida:

Dokumentacja źródłowa:

12. Następne ćwiczenia

Linki do innych modułów z programowania w tym kursie znajdziesz na stronie docelowej kursów z programowania dla zaawansowanych w programie Kotlin (w języku angielskim).