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.
Pakiet Maps SDK na Androida umożliwia zmianę punktu widzenia użytkownika na mapie przez modyfikację kamery 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 reakcji na kliknięcia okienka znacznika lub na gest przeciągania znacznika.
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.
Docelowy (lokalizacja)
Cel kamery to lokalizacja środka mapy określona przez współrzędne geograficzne.
Szerokość geograficzna może się mieścić w zakresie 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 podanie szerokości geograficznej 100 spowoduje 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 linię pionową od środka mapy do jej górnej krawędzi, kierunek będzie odpowiadać kierunkowi kamery (mierzonemu w stopniach) względem prawdziwego północy.
Kierunek 0 oznacza, że górna część mapy wskazuje prawdziwy kierunek północny. Wartość kierunku 90 oznacza, że górna część mapy wskazuje na 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 piechurzy korzystający z mapy i kompasu zwykle orientują mapę tak, aby linia pionowa wskazywała kierunek północny.
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 odpowiada kamerze skierowanej 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 obrazujące ten proces.
Na obrazach poniżej kąt widzenia 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 teraz jest widoczny obszar reprezentowany przez linię w pozycji 4.
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 ponad 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 najbliższą prawidłową wartość, 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 świata na mapie. 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 ją przesunąć, za pomocą 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 Ci CameraUpdate
, który zmienia poziom powiększenia na podana wartość,
pozostawiając wszystkie inne 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 polega na utrwaleniu danego punktu 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. Jest to przydatne np. wtedy, gdy chcesz kontrolować komfort użytkownika, jeśli Twoja 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 widok terenu może mieć mniejsze maksymalne powiększenie niż płytki mapy bazowej.
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 pozostałe właściwości.
CameraUpdateFactory.newLatLngZoom(LatLng, float)
pozwala uzyskać CameraUpdate
, który zmienia szerokość geograficzną, długość geograficzną i powiększenie kamery, zachowując przy tym wszystkie inne 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ę przesuwać 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, co sprawia, że 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środkowywanie mapy w 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 użyć podobnej metody, tworząc element LatLngBounds
i używając elementu CameraUpdateFactory.newLatLngZoom(LatLng latLng, float zoom)
z elementem LatLngBounds
.getCenter()
metody. 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ócona wartość CameraUpdate
spowoduje przesunięcie kamery tak, aby określone wartości LatLngBounds
znalazły się na środku ekranu w ramach danego prostokąta przy największym możliwym poziomie powiększenia, z uwzględnieniem wymaganego marginesu.
Uwaga: prostszą metodę newLatLngBounds(boundary, padding)
do generowania pliku CameraUpdate
stosuj tylko wtedy, gdy ma on służyć do przemieszczania kamery po ułożeniu 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 CameraUpdate
zwracany 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.
ograniczenie przesuwania przez użytkownika do określonego obszaru,
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 ruchów, 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, jak 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 dokończona bez przerwy.
onCancel()
-
Wywoływany, jeśli animacja zostanie przerwana przez wywołanie
stopAnimation()
lub rozpoczęcie nowego ruchu kamery.Może się tak też zdarzyć, jeśli zadzwonisz na numer
GoogleMap.stopAnimation()
.
duration
- Pożądany czas trwania animacji w milisekundach (
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));