Zaawansowany Android w Kotlin 04.1: Mapy Google na Androida

1. Zanim zaczniesz

Tworzenie aplikacji z Mapami Google umożliwia dodawanie do niej funkcji takich jak zdjęcia satelitarne, zaawansowane elementy sterujące interfejsu map, śledzenie lokalizacji i znaczniki lokalizacji. Możesz wzbogacić standardowe Mapy Google, wyświetlając informacje z własnego zbioru danych, np. lokalizacje znanych miejsc do wędkowania lub wspinaczki. Możesz też tworzyć gry, w których gracz eksploruje świat fizyczny, np. w poszukiwaniu skarbów lub w rzeczywistości rozszerzonej.

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

Wymagania wstępne

Znajomość tych zagadnień:

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

Czego się nauczysz

  • Jak uzyskać klucz interfejsu API w Konsoli interfejsów API Google i zarejestrować go w aplikacji
  • Jak zintegrować Mapę Google z aplikacją
  • Jak wyświetlać różne typy map
  • Jak dostosować styl mapy Google
  • Dodawanie znaczników do mapy
  • Jak umożliwić użytkownikowi umieszczenie markera w interesującym miejscu
  • Jak włączyć śledzenie lokalizacji
  • Jak utworzyć aplikację Wander z osadzoną mapą Google
  • Jak tworzyć niestandardowe funkcje aplikacji, takie jak znaczniki i style
  • Jak włączyć śledzenie lokalizacji w aplikacji

2. Aplikacje ogółem

W tym ćwiczeniu utworzysz aplikację Wander, która wyświetla mapę Google z niestandardowym stylem. Aplikacja Wander umożliwia umieszczanie znaczników w lokalizacjach, dodawanie nakładek i wyświetlanie lokalizacji 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 projekt na stronie Interfejsy API i 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 tym laboratorium kodowania użyjesz klucza interfejsu API dla certyfikatu debugowania. Certyfikat debugowania jest z założenia niezabezpieczony, co opisano w artykule Podpisywanie kompilacji do debugowania. Opublikowane aplikacje na Androida, które korzystają z pakietu Maps SDK na Androida, wymagają drugiego klucza API: klucza certyfikatu wersji. Więcej informacji o uzyskiwaniu certyfikatu wersji znajdziesz w artykule Uzyskiwanie 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 z linkiem, który ułatwia uzyskanie klucza interfejsu API.

Krok 1. Utwórz projekt Wander za pomocą 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. Upewnij się, że język to Kotlin.
  3. Kliknij Zakończ.
  4. Gdy aplikacja zostanie utworzona, przyjrzyj się projektowi i tym plikom związanym z Mapami, które Android Studio utworzyło za Ciebie:

google_maps_api.xml – ten plik konfiguracyjny służy do przechowywania klucza interfejsu API. Szablon generuje 2 pliki google_maps_api.xml: jeden do debugowania, a drugi do wersji. Plik klucza interfejsu API dla certyfikatu debugowania znajduje się w katalogu src/debug/res/values. Plik klucza interfejsu API dla certyfikatu wersji znajduje się w katalogu src/release/res/values. W tym module użyjesz tylko certyfikatu debugowania.

activity_maps.xml – ten plik układu zawiera pojedynczy fragment, który wypełnia cały ekran. Klasa SupportMapFragment jest podklasą klasy Fragment. SupportMapFragment to najprostszy sposób na umieszczenie mapy w aplikacji. Jest to otoczka widoku mapy, która automatycznie obsługuje niezbędne potrzeby związane z cyklem życia.

Możesz umieścić SupportMapFragment w pliku układu za pomocą tagu <fragment> w dowolnym tagu ViewGroup z dodatkowym atrybutem name.

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

MapsActivity.java – plik MapsActivity.kt tworzy instancję SupportMapFragment w metodzie onCreate() i używa klasy getMapAsync() do automatycznego inicjowania systemu map i widoku. Aktywność zawierająca SupportMapFragment musi implementować interfejs OnMapReadyCallback i jego metodę onMapReady(). Metoda onMapReady() jest wywoływana po wczytaniu mapy.

Krok 2. Uzyskaj klucz interfejsu API

  1. Otwórz wersję debugowania pliku google_maps_api.xml.
  2. W pliku poszukaj komentarza z długim adresem URL. Parametry adresu URL zawierają szczegółowe informacje o Twojej aplikacji.
  3. Skopiuj adres URL i wklej go w przeglądarce.
  4. Postępuj zgodnie z instrukcjami, aby utworzyć projekt na stronie Interfejsy API i 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, aby 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ę tekst YOUR_KEY_HERE.
  10. Uruchom aplikację. W aktywności powinna być widoczna osadzona mapa ze znacznikiem ustawionym w Sydney w Australii. (Marker Sydney jest częścią szablonu i możesz go później zmienić).

34dc9dd877c90996.png

Krok 3. Zmień nazwę zmiennej mMap

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

  1. W MapsActivity kliknij prawym przyciskiem myszy mMap i kliknij Refactor > Rename...

e713ccb3384450c6.png

  1. Zmień nazwę zmiennej na map.

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

4. Zadanie: dodawanie typów map

Mapy Google obejmują kilka typów map: normalną, hybrydową, satelitarną, terenu i „brak” (bez mapy).

Normalna mapa

Mapa satelitarna

Mapa hybrydowa

Mapa terenu

Każdy typ mapy zawiera inne informacje. Na przykład podczas korzystania z map w nawigacji samochodowej przydatne jest wyświetlanie nazw ulic, więc możesz użyć opcji normalnej. Podczas wędrówki mapa terenu może pomóc Ci określić, ile jeszcze musisz się wspinać, aby dotrzeć na szczyt.

W tym zadaniu:

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

Dodawanie menu 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) > Android Resource File (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 tym kodem, aby utworzyć opcje menu mapy. Typ mapy „brak” został pominięty, ponieważ w jego przypadku nie wyświetla się żadna mapa. Ten krok spowoduje błąd, ale w następnym kroku go rozwiążesz.
<?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 sekcji strings.xml dodaj zasoby dla atrybutów title, aby rozwiązać 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. MapsActivity zastąp metodę onCreateOptionsMenu() i utwórz menu z pliku zasobu 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 różnych trybach.

6fa42970d87f5dc7.png

5. Zadanie: dodawanie znaczników

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

W tym zadaniu spowodujesz, że kamera mapy przesunie się do Twojego domu, powiększy obraz do określonego poziomu i umieści 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ę. Twoja metoda powinna teraz wyglądać tak:
override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

}
  1. Aby znaleźć szerokość i długość geograficzną swojego domu, wykonaj te czynności.
  2. Utwórz wartość szerokości i długości geograficznej, a następnie 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 bardzo chcesz powiększyć mapę. Użyj poziomu powiększenia 15f.
val zoomLevel = 15f

Poziom powiększenia określa, jak bardzo powiększona jest mapa. Poniższa lista pokazuje przybliżony poziom szczegółowości na poszczególnych poziomach powiększenia:

  • 1: świat
  • 5: ląd/kontynent
  • 10: miasto
  • 15: ulice
  • 20: budynki,
  1. Przesuń kamerę do pozycji homeLatLng, wywołując funkcję moveCamera() na obiekcie map i przekazując obiekt CameraUpdate za pomocą CameraUpdateFactory.newLatLngZoom(). Przekaż obiekt homeLatLngzoomLevel.
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
  1. Dodaj znacznik do mapy w lokalizacji 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ę do Twojego domu, powiększyć do wybranego poziomu i umieścić na nim znacznik.

fc939024778ee76.png

Krok 2. Zezwól użytkownikom na dodawanie znacznika za pomocą długiego kliknięcia

W tym kroku dodasz znacznik, gdy użytkownik naciśnie i przytrzyma lokalizację na mapie.

  1. Utwórz w MapsActivity metodę setMapLongClick(), która przyjmuje argument GoogleMap.
  2. Dołącz setOnMapLongClickListener detektor do obiektu mapy.
private fun setMapLongClick(map:GoogleMap) {
   map.setOnMapLongClickListener { }
}
  1. setOnMapLongClickListener() wywołaj metodę addMarker(). Przekaż nowy obiekt MarkerOptions z ustawioną pozycją na przekazaną wartość LatLng.
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. Na końcu metody onMapReady() wywołaj funkcję setMapLongClick() z argumentem map.
override fun onMapReady(googleMap: GoogleMap) {
   ...
  
   setMapLongClick(map)
}
  1. Uruchom aplikację.
  2. Kliknij i przytrzymaj mapę, aby umieścić znacznik w wybranej lokalizacji.
  3. Kliknij znacznik, aby wyśrodkować go na ekranie.

4ff8d1c1db3bca9e.png

Krok 3. Dodaj okno informacji do znacznika

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

  1. W usłudze setMapLongClick()setOnMapLongClickListener() utwórz val dla snippet. Fragment to dodatkowy tekst wyświetlany po tytule. W wyświetlanym fragmencie kodu zobaczysz 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. addMarker() ustaw title znacznika na „Przypięty znacznik” za pomocą zasobu tekstowego R.string.dropped_pin.
  2. Ustaw wartość snippet znacznika na snippet.

Gotowa 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. Kliknij i przytrzymaj mapę, aby umieścić na niej znacznik lokalizacji.
  3. Kliknij znacznik, aby wyświetlić okno informacji.

63f210e6e47dfa29.png

Krok 4. Dodaj odbiornik POI

Domyślnie na mapie wyświetlają się ciekawe miejsca wraz z odpowiadającymi im ikonami. Obejmują one parki, szkoły, budynki rządowe i inne. Gdy typ mapy jest ustawiony na normal, na mapie pojawiają się też punkty POI firm. Punkty POI firm reprezentują firmy, takie jak sklepy, restauracje i hotele.

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

  1. Utwórz w MapsActivity metodę setPoiClick(), która przyjmuje argument GoogleMap.
  2. W metodzie setPoiClick() ustaw OnPoiClickListener na przekazanym GoogleMap.
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->

   }
}
  1. setOnPoiClickListener() utwórz val poiMarker dla znacznika .
  2. Ustaw go na znacznik za pomocą map.addMarker(), a następnie ustaw MarkerOptions na title, czyli nazwę ciekawego miejsca.
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()poiMarker, aby natychmiast wyświetlić okno informacji.
poiMarker.showInfoWindow()

Ostateczny 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 pliku onMapReady() wywołaj funkcję setPoiClick() i przekaż do niej wartość map.
override fun onMapReady(googleMap: GoogleMap) {
   ...

   setPoiClick(map)
}
  1. Uruchom aplikację i znajdź punkt POI, np. park lub kawiarnię.
  2. Kliknij punkt POI, aby umieścić na nim znacznik i wyświetlić nazwę tego punktu w okienku informacyjnym.

f4b0972c75d5fa5f.png

6. Zadanie: nadaj styl mapie

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

Obiekt MapFragment możesz dostosować za pomocą dostępnych atrybutów XML, tak jak każdy inny fragment. W tym kroku dostosujesz jednak wygląd i styl treści elementu MapFragment za pomocą metod obiektu GoogleMap.

Aby utworzyć niestandardowy styl mapy, wygeneruj plik JSON, który określa sposób wyświetlania elementów na mapie. Nie musisz tworzyć tego pliku JSON ręcznie. Google udostępnia Kreator stylów w Google Maps Platform, który generuje kod JSON po wizualnym dostosowaniu mapy. W tym zadaniu nadajesz mapie styl retro, co oznacza, że używasz kolorów w stylu vintage i dodajesz kolorowe drogi.

Krok 1. Utwórz styl mapy

  1. W przeglądarce otwórz stronę https://mapstyle.withgoogle.com/.
  2. Kliknij Utwórz styl.
  3. Kliknij Retro.

208b3d3aeab0d9b6.png

  1. Kliknij Więcej opcji.

4a35faaf9535ee82.png

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

92c3293749293a4c.png

  1. Kliknij Zakończ.

f1bfe8585eb69480.png

  1. Skopiuj kod JSON z wyświetlonego okna i w razie potrzeby zapisz go w notatniku w formacie zwykłego tekstu, aby użyć go 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. Zasoby katalogu raw są używane jako kod JSON.
  2. Utwórz w katalogu res/raw plik o nazwie map_style.json.
  3. Wklej zapisany kod JSON do nowego pliku zasobu.
  4. W MapsActivity utwórz zmienną klasy TAG powyżej metody onCreate(). Jest to używane do celów rejestrowania.
private val TAG = MapsActivity::class.java.simpleName
  1. MapsActivity utwórz też funkcję setMapStyle(), która przyjmuje argument GoogleMap.
  2. setMapStyle() dodaj blok try{}.
  3. W bloku try{} utwórz val success, aby sprawdzić, czy stylizacja się powiodła. (Dodaj ten blok catch).
  4. W bloku try{} ustaw styl JSON na mapę i wywołaj setMapStyle() na obiekcie GoogleMap. Przekaż obiekt MapStyleOptions, który wczytuje plik JSON.
  5. Przypisz wynik do success. Metoda setMapStyle() zwraca wartość logiczną wskazującą stan powodzenia analizy pliku stylu i ustawienia 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ę warunkową dla wartości success równej false. Jeśli stylizacja się nie powiedzie, wydrukuj dziennik z informacją 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ć sytuację, w której brakuje pliku stylu. Jeśli w bloku catch nie można wczytać pliku, zgłoś błąd 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ć jak w tym fragmencie kodu:

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(), przekazując do niej obiekt GoogleMap.
override fun onMapReady(googleMap: GoogleMap) {
   ...
   setMapStyle(map)
}
  1. Uruchom aplikację.
  2. Ustaw mapę w trybie normal. Nowy styl powinien być widoczny z motywem retro i drogami w wybranym kolorze.

b59d6cb81f02a14f.png

Krok 3. Nadaj znacznikowi styl

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

  1. W metodzie onMapLongClick() dodaj do MarkerOptions() konstruktora ten wiersz kodu, aby użyć domyślnego znacznika, 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ę. Markery, które pojawiają się po długim kliknięciu, są teraz niebieskie. Zwróć uwagę, że markery POI są nadal czerwone, ponieważ nie dodano stylu do metody onPoiClick().

b9916bca3c367e3.png

7. Zadanie: dodawanie nakładki

Jednym ze sposobów dostosowania mapy Google jest rysowanie na niej. Ta technika jest przydatna, jeśli chcesz wyróżnić określony typ lokalizacji, np. popularne miejsca do wędkowania.

  • Kształty: do mapy możesz dodawać linie łamane, wielokątyokręgi.
  • GroundOverlay obiekty: nakładka na teren to obraz przypisany do mapy. W przeciwieństwie do znaczników nakładki na ziemię są zorientowane na powierzchnię Ziemi, a nie na ekran. Obracanie, pochylanie lub powiększanie mapy zmienia orientację obrazu. Nakładki na ziemię są przydatne, gdy chcesz umieścić pojedynczy obraz w jednym obszarze na mapie.

Krok: dodawanie nakładki na ziemię

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

  1. Pobierz ten obraz Androida i zapisz go w folderze res/drawable. (Upewnij się, że plik ma nazwę android.png).

61fabd56a0841b44.png

  1. onMapReady() po wywołaniu funkcji przenoszącej kamerę do pozycji w domu utwórz obiekt GroundOverlayOptions.
  2. Przypisz obiekt do zmiennej o nazwie androidOverlay.
val androidOverlay = GroundOverlayOptions()
  1. Użyj metody BitmapDescriptorFactory.fromResource(), aby utworzyć obiekt BitmapDescriptor z pobranego zasobu obrazu.
  2. Przekaż wynikowy obiekt BitmapDescriptor do metody image() obiektu GroundOverlayOptions.
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
  1. Utwórz float overlaySize dla szerokości w metrach żądanej nakładki. W tym przykładzie dobrze sprawdzi się szerokość 100f.

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

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

b1b25b0acd6a9807.png

8. Zadanie: włącz śledzenie lokalizacji

Użytkownicy często korzystają z Map Google, aby sprawdzić swoją bieżącą 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 ten przycisk, mapa wyśrodkuje się na lokalizacji urządzenia. Lokalizacja jest oznaczona niebieskim punktem, jeśli urządzenie jest nieruchome, lub niebieskim szewronem, jeśli urządzenie się porusza.

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

Krok: poproś o dostęp do lokalizacji

Włączenie śledzenia lokalizacji w Mapach Google wymaga tylko jednej linijki kodu. Musisz jednak upewnić się, że użytkownik przyznał uprawnienia do lokalizacji (za pomocą modelu uprawnień w czasie działania).

Na tym etapie wysyłasz prośbę o dostęp do lokalizacji i włączasz śledzenie lokalizacji.

  1. W pliku AndroidManifest.xml sprawdź, czy uprawnienie FINE_LOCATION jest już obecne. Android Studio wstawiło to uprawnienie, gdy wybrano szablon Map Google.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. MapsActivity utwórz zmienną klasy REQUEST_LOCATION_PERMISSION.
private val REQUEST_LOCATION_PERMISSION = 1
  1. Aby sprawdzić, czy uprawnienia zostały przyznane, utwórz w MapsActivity metodę o nazwie isPermissionGranted(). W tej metodzie sprawdź, czy użytkownik przyznał uprawnienia.
private fun isPermissionGranted() : Boolean {
  return ContextCompat.checkSelfPermission(
       this,
      Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
  1. Aby włączyć śledzenie lokalizacji w aplikacji, utwórz w pliku MapsActivity metodę o nazwie enableMyLocation(), która nie przyjmuje argumentów i nie zwraca żadnych wartości. Sprawdź, czy jest tam uprawnienie ACCESS_FINE_LOCATION. Jeśli uprawnienia zostały przyznane, włącz warstwę lokalizacji. W przeciwnym razie poproś o uprawnienia.
private fun enableMyLocation() {
   if (isPermissionGranted()) {
       map.isMyLocationEnabled = true 
   }
   else {
       ActivityCompat.requestPermissions(
           this,
           arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
           REQUEST_LOCATION_PERMISSION
       )
   }
}
  1. Aby włączyć warstwę lokalizacji, wywołaj funkcję enableMyLocation() z wywołania zwrotnego onMapReady().
override fun onMapReady(googleMap: GoogleMap) {
   ...
   enableMyLocation()
}
  1. Zastąp metodę onRequestPermissionsResult(). Sprawdź, czy requestCode jest równe REQUEST_LOCATION_PERMISSION. Jeśli tak jest, oznacza to, że uprawnienie zostało przyznane. Jeśli uprawnienie zostało przyznane, sprawdź też, czy tablica grantResults zawiera w pierwszym miejscu wartość PackageManager.PERMISSION_GRANTED. Jeśli tak jest, zadzwoń pod numer 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

Na mapie pojawi się niebieski punkt wskazujący bieżącą lokalizację urządzenia. Zwróć uwagę na przycisk lokalizacji. Jeśli przesuniesz mapę poza swoją lokalizację i klikniesz ten przycisk, mapa zostanie ponownie wyśrodkowana na lokalizacji urządzenia.

5b12eda7f467bc2f.png

9. Kod rozwiązania

Pobierz kod ukończonego ćwiczenia.

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

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

10. Podsumowanie

Gratulacje! Dodano mapę Google do aplikacji na Androida w języku Kotlin i zmieniono jej styl.

11. Więcej informacji

Dokumentacja dla deweloperów aplikacji na Androida:

Dokumentacja:

12. Następne ćwiczenie

Linki do innych ćwiczeń w Codelabs w tym kursie znajdziesz na stronie docelowej ćwiczeń w Codelabs z zaawansowanego Androida w Kotlinie.