Mapy w pakiecie Maps SDK na Androida można przechylać i obracać za pomocą prostych gestów, co umożliwia użytkownikom dostosowanie mapy do ich potrzeb. Na dowolnym poziomie powiększenia możesz przesuwać mapę lub zmieniać jej perspektywę z bardzo małym opóźnieniem dzięki mniejszemu rozmiarowi pikselów kafelków mapy opartej na wektorach.
Przykładowe fragmenty kodu
Repozytorium ApiDemos na GitHubie zawiera przykład, który demonstruje funkcje aparatu:
- CameraDemoActivity – Kotlin: zmiana pozycji kamery
- CameraDemoActivity – Java: zmiana pozycji kamery
Wprowadzenie
Podobnie jak Mapy Google w internecie, pakiet SDK Map Google na Androida przedstawia powierzchnię Ziemi (kulę) na ekranie urządzenia (płaskiej płaszczyźnie) za pomocą projekcji Mercatora. W kierunku wschodnim i zachodnim mapa jest powtarzana w nieskończoność, ponieważ świat płynnie łączy się z samym sobą. W kierunku północnym i południowym mapa jest ograniczona do około 85 stopni szerokości geograficznej północnej i 85 stopni szerokości geograficznej południowej.
Uwaga: w projekcji Mercatora szerokość jest ograniczona wzdłuż, ale wysokość jest nieskończona w szerz. „Odcinamy” obrazy mapy podstawowej, korzystając z projekcji Mercatora z przybliżeniem +/- 85°, aby uzyskać kwadratowy kształt mapy, co ułatwia logikę wyboru płytek.
Maps SDK na Androida umożliwia zmianę punktu widzenia użytkownika na mapie przez modyfikowanie aparatu mapy.
Zmiany w aparacie nie wpłyną na dodane przez Ciebie znaczniki, nakładki ani inne elementy graficzne, ale warto je dostosować do nowego widoku.
Ponieważ możesz odbierać gesty użytkownika na mapie, możesz zmieniać mapę w odpowiedzi na prośby użytkownika. Na przykład metoda wywołania zwrotnego OnMapClickListener.onMapClick()
reaguje na pojedyncze kliknięcie na mapie. Metoda otrzymuje współrzędne geograficzne położenia, więc możesz na nie odpowiedzieć, przesuwając lub przybliżając widok.
Podobne metody są dostępne w przypadku klikania dymka znacznika lub
reagowania na gest przeciągania na znaczniku.
Możesz też słuchać dźwięków związanych z ruchy kamery, dzięki czemu aplikacja otrzyma powiadomienie, gdy kamera zacznie się poruszać, będzie się poruszać lub przestanie się poruszać. Szczegółowe informacje znajdziesz w przewodniku dotyczącym zdarzeń zmiany kamery.
Pozycja kamery
Widok mapy jest modelowany jako kamera skierowana w dół na płaską powierzchnię. Pozycja kamery (a zatem renderowanie mapy) jest określana przez te właściwości: cel (szerokość/długość geograficzna), kierunek, pochylenie i powiększenie.
Cel (lokalizacja)
Docelowy punkt kamery to lokalizacja środka mapy, określona jako współrzędne geograficzne.
Szerokość geograficzna może się mieścić w przedziale od –85 do 85 stopni. Wartości powyżej lub poniżej tego zakresu zostaną przycięte do najbliższej wartości w tym zakresie. Na przykład szerokość geograficzna równa 100 powoduje ustawienie wartości 85. Długość geograficzna może przyjmować wartości od -180 do 180 stopni włącznie. Wartości powyżej lub poniżej tego zakresu zostaną zaokrąglone tak, aby mieściły się w zakresie (-180, 180). Na przykład 480, 840 i 1200 zostaną zaokrąglone do 120 stopni.Kierunek (orientacja)
Kierunek kamery określa kierunek kompasu mierzony w stopniach od prawdziwego północy, odpowiadający górnej krawędzi mapy. Jeśli narysujesz pionową linię od środka mapy do górnej krawędzi mapy, przesunięcie będzie odpowiadać kierunku kamery (mierzone w stopniach) względem rzeczywistej północy.
Kierunek 0 oznacza, że górna część mapy wskazuje prawdziwy kierunek północny. Wartość kierunku 90 oznacza, że góra mapy jest skierowana we wschód (90 stopni na kompasie). Wartość 180 oznacza, że górna część mapy wskazuje na południe.
Interfejs Maps API umożliwia zmianę kierunku mapy. Na przykład osoba jadąca samochodem często obraca mapę drogową, aby dopasować ją do kierunku jazdy, a turyści korzystający z mapy i kompasu zwykle konfigurują mapę tak, aby linia pionowa wskazywała północ.
Przechylenie (kąt widzenia)
Pochylenie określa położenie kamery na łuku bezpośrednio nad środkiem mapy, mierzone w stopniach od nadir (kierunku wskazującego bezpośrednio pod kamerę). Wartość 0 oznacza, że kamera jest skierowana prosto w dół. Wartości większe niż 0 odpowiadają kamerze skierowanej w kierunku horyzontu o określoną liczbę stopni. Gdy zmienisz kąt widzenia, mapa będzie wyglądać w perspektywie, a elementy znajdujące się daleko będą wydawać się mniejsze, a te znajdujące się blisko – większe. Poniżej znajdziesz ilustracje pokazujące ten proces.
Na poniższych obrazach kąt patrzenia wynosi 0 stopni. Pierwsze zdjęcie przedstawia schematyczną wersję tego procesu: pozycja 1 to pozycja kamery, a pozycja 2 to bieżąca pozycja na mapie. Poniżej wyświetla się mapa.
Na obrazach poniżej kąt widzenia wynosi 45 stopni. Zwróć uwagę, że kamera przesuwa się o połowę łuku między pozycją na wprost nad głową (0 stopni) a pozycją na wysokości ziemi (90 stopni) do pozycji 3. Kamera nadal wskazuje środek mapy, ale obszar reprezentowany przez linię w pozycji 4 jest teraz widoczny.
Na tym zrzucie ekranu mapa jest nadal wyśrodkowana w tym samym miejscu co na oryginalnej mapie, ale u góry pojawiło się więcej funkcji. Gdy zwiększysz kąt powyżej 45 stopni, elementy między kamerą a pozycją na mapie będą się wydawać proporcjonalnie większe, a elementy poza pozycją na mapie będą wydawać się proporcjonalnie mniejsze, co spowoduje efekt trójwymiarowości.
Zoom
Poziom powiększenia aparatu określa skalę mapy. Przy większym powiększeniu na ekranie widać więcej szczegółów, a przy mniejszym – więcej obszaru. Przy poziomie powiększenia 0 skala mapy jest taka, że cała mapa świata ma szerokość około 256 dp (pikseli niezależnych od gęstości).
Zwiększenie poziomu powiększenia o 1 podwaja szerokość świata na ekranie. Dlatego przy poziomie powiększenia N szerokość świata wynosi około 256 × 2N dp. Na przykład przy powiększeniu 2 cały świat ma około 1024 dp szerokości.
Poziom powiększenia nie musi być liczbą całkowitą. Zakres poziomów powiększenia dozwolonych na mapie zależy od wielu czynników, w tym od celu, typu mapy i rozmiaru ekranu. Każda liczba spoza zakresu zostanie przekonwertowana na wartość najbliższą z dozwolonych, która może być minimalnym lub maksymalnym powiększeniem. 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
Przesuwanie kamery
Interfejs API Map umożliwia zmianę widocznej części mapy. Osiąga się to przez zmianę pozycji kamery (a nie przez przesuwanie mapy).
Gdy zmieniasz kamerę, możesz animować ruch kamery. Animacja interpoluje między bieżącymi atrybutami kamery a nowymi atrybutami kamery. Możesz też kontrolować czas trwania animacji.
Aby zmienić pozycję kamery, musisz określić, dokąd chcesz ją przesunąć, za pomocą elementu CameraUpdate
. Interfejs Maps API umożliwia tworzenie wielu różnych typów CameraUpdate
za pomocą CameraUpdateFactory
. Dostępne są te ustawienia:
Zmienianie poziomu powiększenia i ustawianie minimalnego/maksymalnego powiększenia
CameraUpdateFactory.zoomIn()
i CameraUpdateFactory.zoomOut()
dają CameraUpdate
, który zmienia poziom powiększenia o 1,0, zachowując przy tym wszystkie inne właściwości.
CameraUpdateFactory.zoomTo(float)
daje CameraUpdate
, który zmienia poziom powiększenia na podaną wartość, zachowując wszystkie pozostałe właściwości bez zmian.
CameraUpdateFactory.zoomBy(float)
i
CameraUpdateFactory.zoomBy(float, Point)
dają CameraUpdate
, który zwiększa (lub zmniejsza, jeśli wartość jest ujemna) poziom powiększenia o podawaną wartość. Druga opcja pozwala ustawić dany punkt na ekranie tak, aby pozostał w tej samej lokalizacji (szerokość/długość geograficzna). Aby to osiągnąć, może zmienić położenie kamery.
Możesz ustawić preferowany minimalny lub maksymalny poziom powiększenia. Może to być przydatne np. do kontrolowania wrażeń użytkownika, jeśli aplikacja wyświetla zdefiniowany obszar wokół punktu zainteresowania lub jeśli używasz niestandardowej nakładki z ograniczonym zestawem poziomów powiększenia.
Kotlin
private lateinit var map: GoogleMap map.setMinZoomPreference(6.0f) map.setMaxZoomPreference(14.0f)
Java
private GoogleMap map; map.setMinZoomPreference(6.0f); map.setMaxZoomPreference(14.0f);
Pamiętaj, że istnieją ograniczenia techniczne, które mogą uniemożliwić użytkownikom zbyt duże lub zbyt małe przybliżenie. Na przykład widok satelitarny lub teren może być mniejszy niż dla elementów mapy podstawowej.
Zmiana pozycji kamery
Dostępne są 2 wygodne metody zmiany pozycji.
CameraUpdateFactory.newLatLng(LatLng)
daje Ci CameraUpdate
, który zmienia szerokość i długość geograficzną kamery,
pozostawiając wszystkie inne właściwości.
CameraUpdateFactory.newLatLngZoom(LatLng, float)
udostępnia przycisk CameraUpdate
, który zmienia szerokość, długość geograficzną i powiększenie kamery przy zachowaniu wszystkich pozostałych właściwości.
Aby mieć pełną swobodę zmiany pozycji kamery, użyj CameraUpdateFactory.newCameraPosition(CameraPosition)
, która umożliwia użycie CameraUpdate
, aby przesunąć kamerę do danej pozycji. CameraPosition
można uzyskać bezpośrednio, za pomocą new CameraPosition()
lub za pomocą CameraPosition.Builder
za pomocą new CameraPosition.Builder()
.
Przesuwanie (przewijanie)
CameraUpdateFactory.scrollBy(float, float)
zwraca CameraUpdate
, który zmienia współrzędne geograficzne kamery w taki sposób, że mapa przesuwa się o określoną liczbę pikseli. Dodatnia wartość x powoduje przesunięcie kamery w prawo, przez co mapa wydaje się przesunięta w lewo. Dodatnia wartość y powoduje przesunięcie kamery w dół, przez co mapa wydaje się przesunięta w górę. Z kolei ujemne wartości x powodują przesunięcie kamery w lewo, przez co mapa wydaje się przesunięta w prawo, a ujemne wartości y powodują przesunięcie kamery w górę. Przewijanie jest względne do bieżącej orientacji kamery. Jeśli na przykład kamera ma kierunek 90 stopni, wschodnia strona świata jest „na górze”.
Wyznaczanie granic
Ustawianie granic mapy
Czasami warto przesunąć kamerę, aby cały obszar, który Cię interesuje, był widoczny przy maksymalnym możliwym poziomie powiększenia. Jeśli np. wyświetlasz wszystkie stacje benzynowe w odległości 8 km od bieżącej pozycji użytkownika, możesz przesunąć kamerę, aby wszystkie były widoczne na ekranie. Aby to zrobić, najpierw oblicz wartość LatLngBounds
, która ma być widoczna na ekranie. Następnie możesz użyć CameraUpdateFactory.newLatLngBounds(LatLngBounds bounds, int
padding)
, aby uzyskać CameraUpdate
, który zmienia pozycję kamery tak, aby dany LatLngBounds
mieścił się całkowicie na mapie, biorąc pod uwagę określony margines (w pikselach). Zwrócona wartość CameraUpdate
zapewnia, że odstęp (w pikselach) między określonymi granicami a brzegiem mapy będzie co najmniej tak duży jak określony margines. Pamiętaj, że pochylenie i kierunek mapy będą miały wartość 0.
Kotlin
val australiaBounds = LatLngBounds( LatLng((-44.0), 113.0), // SW bounds LatLng((-10.0), 154.0) // NE bounds ) map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0))
Java
LatLngBounds australiaBounds = new LatLngBounds( new LatLng(-44, 113), // SW bounds new LatLng(-10, 154) // NE bounds ); map.moveCamera(CameraUpdateFactory.newLatLngBounds(australiaBounds, 0));
Wyśrodkowanie mapy na obszarze
W niektórych przypadkach możesz chcieć wyśrodkować kamerę w ramach określonych granic, zamiast uwzględniać jej skrajne krawędzie. Na przykład, aby wyśrodkować kamerę na kraju, zachowując stały zoom. W takim przypadku możesz skorzystać z podobnej metody, tworząc LatLngBounds
i używając CameraUpdateFactory.newLatLngZoom(LatLng latLng, float zoom)
z LatLngBounds
.Metoda getCenter()
. Metoda getCenter() zwraca geograficzny środek LatLngBounds
.
Kotlin
val australiaBounds = LatLngBounds( LatLng((-44.0), 113.0), // SW bounds LatLng((-10.0), 154.0) // NE bounds ) map.moveCamera(CameraUpdateFactory.newLatLngZoom(australiaBounds.center, 10f))
Java
LatLngBounds australiaBounds = new LatLngBounds( new LatLng(-44, 113), // SW bounds new LatLng(-10, 154) // NE bounds ); map.moveCamera(CameraUpdateFactory.newLatLngZoom(australiaBounds.getCenter(), 10));
Przeciążenie metody newLatLngBounds(boundary, width, height,
padding)
umożliwia określenie szerokości i wysokości prostokąta w pikselach, tak aby odpowiadały one wymiarom mapy. Prostokąt jest tak umieszczony, aby jego środek pokrywał się ze środkiem widoku mapy (tak więc jeśli określone wymiary są takie same jak wymiary widoku mapy, prostokąt pokrywa się z widokiem mapy). Zwrócony obiekt CameraUpdate
przesunie kamerę w taki sposób, że określony element LatLngBounds
zostanie wyśrodkowany na ekranie wewnątrz danego prostokąta przy największym możliwym poziomie powiększenia (uwzględniając wymagane dopełnienie).
Uwaga: używaj prostszej metody newLatLngBounds(boundary, padding)
do generowania CameraUpdate
tylko wtedy, gdy będzie ona używana do przesuwania kamery po zmianie układu mapy. Podczas tworzenia układu interfejs API oblicza wyświetlane granice mapy, które są potrzebne do prawidłowego wyświetlania ramki ograniczającej. Natomiast dane CameraUpdate
zwracane przez bardziej złożoną metodę newLatLngBounds(boundary, width, height, padding)
możesz używać w dowolnym momencie, nawet zanim mapa zostanie poddawana układowi, ponieważ interfejs API oblicza granice wyświetlania na podstawie przekazanych argumentów.
Ograniczanie przesuwania w danym obszarze przez użytkownika
W wymienionych powyżej scenariuszach określasz granice mapy, ale użytkownik może przewijać lub przesuwać widok poza te granice. Zamiast tego możesz ograniczyć zakres współrzędnych X i Y punktu centralnego mapy (celu kamery), aby użytkownicy mogli przewijać i przesuwać mapę tylko w tych granicach. Na przykład aplikacja sklepu w centrum handlowym lub na lotnisku może ograniczać mapę do określonych granic, umożliwiając użytkownikom przewijanie i przesuwanie w tych granicach.
Kotlin
// Create a LatLngBounds that includes the city of Adelaide in Australia. val adelaideBounds = LatLngBounds( LatLng(-35.0, 138.58), // SW bounds LatLng(-34.9, 138.61) // NE bounds ) // Constrain the camera target to the Adelaide bounds. map.setLatLngBoundsForCameraTarget(adelaideBounds)
Java
// Create a LatLngBounds that includes the city of Adelaide in Australia. LatLngBounds adelaideBounds = new LatLngBounds( new LatLng(-35.0, 138.58), // SW bounds new LatLng(-34.9, 138.61) // NE bounds ); // Constrain the camera target to the Adelaide bounds. map.setLatLngBoundsForCameraTarget(adelaideBounds);
Ten diagram przedstawia sytuację, w której cel kamery jest ograniczony do obszaru nieco większego niż widoczny obszar. Użytkownik może przewijać i przesuwać obraz, o ile obiektyw kamery pozostaje w ograniczonym obszarze. Krzyżyk oznacza cel kamery:
Mapa zawsze wypełnia widoczny obszar, nawet jeśli oznacza to, że widoczny obszar obejmuje obszary poza zdefiniowanymi granicami. Jeśli na przykład umieścisz punkt docelowy kamery w rogu ograniczonego obszaru, obszar za rogiem będzie widoczny w widocznym obszarze, ale użytkownicy nie będą mogli przewinąć dalej w tym kierunku. Ten diagram przedstawia ten scenariusz. Krzyż oznacza cel kamery:
Na poniższym diagramie cel kamery ma bardzo ograniczone granice, co daje użytkownikowi niewielką możliwość przewijania lub przesuwania mapy. Krzyżyk reprezentuje cel kamery:
Aktualizuję widok z kamery
Aby zastosować CameraUpdate
na mapie, możesz przesunąć kamerę natychmiast lub płynnie. Aby natychmiast przesunąć kamerę w danym CameraUpdate
, możesz wywołać funkcję GoogleMap.moveCamera(CameraUpdate)
.
Możesz zwiększyć wygodę użytkowników, zwłaszcza w przypadku krótkich przekształceń, przez animację zmian. Aby to zrobić, zamiast dzwonić GoogleMap.moveCamera
zadzwoń
GoogleMap.animateCamera
.
Mapy będą płynnie przechodzić na nowe atrybuty. Najbardziej szczegółowa forma tej metody,
GoogleMap.animateCamera(cameraUpdate, duration, callback)
,
oferuje 3 argumenty:
cameraUpdate
CameraUpdate
opisujący, gdzie przesunąć kamerę.callback
- Obiekt implementujący
GoogleMap.CancellableCallback
. Ten ogólny interfejs do obsługi zadań definiuje 2 metody: onCancel() i onFinished(). W przypadku animacji metody są wywoływane w tych okolicznościach:onFinish()
- Wywoływany, gdy animacja zostanie ukończona bez przerwy.
onCancel()
-
Wywoływany, jeśli animacja zostanie przerwana przez wywołanie
stopAnimation()
lub rozpoczęcie nowego ruchu kamery.Ten problem może też wystąpić, gdy wywołasz metodę
GoogleMap.stopAnimation()
.
duration
- Pożądany czas trwania animacji (w milisekundach) jako
int
.
Poniższe fragmenty kodu pokazują kilka typowych sposobów przemieszczania kamery.
Kotlin
val sydney = LatLng(-33.88, 151.21) val mountainView = LatLng(37.4, -122.1) // Move the camera instantly to Sydney with a zoom of 15. map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 15f)) // Zoom in, animating the camera. map.animateCamera(CameraUpdateFactory.zoomIn()) // Zoom out to zoom level 10, animating with a duration of 2 seconds. map.animateCamera(CameraUpdateFactory.zoomTo(10f), 2000, null) // Construct a CameraPosition focusing on Mountain View and animate the camera to that position. val cameraPosition = CameraPosition.Builder() .target(mountainView) // Sets the center of the map to Mountain View .zoom(17f) // Sets the zoom .bearing(90f) // Sets the orientation of the camera to east .tilt(30f) // Sets the tilt of the camera to 30 degrees .build() // Creates a CameraPosition from the builder map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
Java
LatLng sydney = new LatLng(-33.88,151.21); LatLng mountainView = new LatLng(37.4, -122.1); // Move the camera instantly to Sydney with a zoom of 15. map.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 15)); // Zoom in, animating the camera. map.animateCamera(CameraUpdateFactory.zoomIn()); // Zoom out to zoom level 10, animating with a duration of 2 seconds. map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null); // Construct a CameraPosition focusing on Mountain View and animate the camera to that position. CameraPosition cameraPosition = new CameraPosition.Builder() .target(mountainView ) // Sets the center of the map to Mountain View .zoom(17) // Sets the zoom .bearing(90) // Sets the orientation of the camera to east .tilt(30) // Sets the tilt of the camera to 30 degrees .build(); // Creates a CameraPosition from the builder map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));