Mapy w pakiecie Maps SDK na Androida można przechylać i obracać za pomocą prostych gestów, co pozwala użytkownikom dostosowywać orientację mapy do swoich potrzeb. Na każdym poziomie powiększenia możesz przesuwać mapę lub zmieniać jej perspektywę z bardzo małym opóźnieniem dzięki mniejszemu rozmiarowi kafelków mapy wektorowej.
Przykładowe fragmenty kodu
Repozytorium ApiDemos na GitHubie zawiera przykład, który pokazuje 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 (sferę) na ekranie urządzenia (płaskiej powierzchni) za pomocą projekcji Merkatora. W kierunku wschód-zachód mapa powtarza się w nieskończoność, ponieważ świat płynnie się na niej zawija. 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: projekcja Mercatora ma skończoną szerokość w kierunku podłużnym, ale nieskończoną wysokość w kierunku poprzecznym. Obrazy mapy bazowej „odcinamy” przy użyciu projekcji Mercatora przy około +/- 85 stopniach, aby uzyskać kwadratowy kształt mapy, co ułatwia wybieranie kafelków.
Pakiet Maps SDK na Androida umożliwia zmianę punktu widzenia użytkownika na mapę przez modyfikowanie kamery mapy.
Zmiany w kamerze nie wpłyną na markery, nakładki ani inne dodane przez Ciebie elementy graficzne, ale możesz je zmienić, aby lepiej pasowały do nowego widoku.
Możesz nasłuchiwać gestów użytkownika na mapie i zmieniać ją w odpowiedzi na jego prośby. Na przykład metoda wywołania zwrotnego OnMapClickListener.onMapClick() reaguje na pojedyncze kliknięcie mapy. Metoda otrzymuje szerokość i długość geograficzną miejsca dotknięcia, więc możesz odpowiedzieć, przesuwając lub powiększając widok do tego punktu.
Podobne metody są dostępne w przypadku reagowania na kliknięcia dymka znacznika lub na przeciągnięcie znacznika.
Możesz też nasłuchiwać ruchów kamery, aby aplikacja otrzymywała powiadomienia, gdy kamera zaczyna się poruszać, porusza się lub przestaje się poruszać. Więcej informacji znajdziesz w przewodniku po zdarzeniach związanych ze zmianą kamery.
Pozycja kamery
Widok mapy jest modelowany jako kamera skierowana w dół na płaską powierzchnię. Położenie kamery (a tym samym renderowanie mapy) jest określone przez te właściwości: target (lokalizacja określona przez szerokość i długość geograficzną), bearing, tilt i zoom.
Miejsce docelowe (lokalizacja)
Punkt docelowy kamery to lokalizacja środka mapy określona za pomocą współrzędnych geograficznych.
Szerokość geograficzna może się zawierać w zakresie od -85 do 85 stopni. Wartości powyżej lub poniżej tego zakresu zostaną zmienione na najbliższą wartość w tym zakresie. Na przykład podanie szerokości geograficznej 100 spowoduje ustawienie wartości 85. Długość geograficzna mieści się w zakresie od -180 do 180 stopni włącznie. Wartości powyżej lub poniżej tego zakresu zostaną przekształcone tak, aby mieściły się w zakresie (-180, 180). Na przykład wartości 480, 840 i 1200 zostaną zaokrąglone do 120 stopni.Kierunek (orientacja)
Kierunek kamery określa kierunek kompasu mierzony w stopniach od północy geograficznej, który odpowiada górnej krawędzi mapy. Jeśli narysujesz pionową linię od środka mapy do jej górnej krawędzi, uzyskasz kierunek, w którym jest skierowany obiektyw (mierzony w stopniach) względem północy geograficznej.
Wartość 0 oznacza, że górna część mapy wskazuje północ geograficzną. Wartość 90 oznacza, że górna część mapy jest skierowana na wschód (90 stopni na kompasie). Wartość 180 oznacza, że górna część mapy jest skierowana na południe.
Interfejs API Map Google umożliwia zmianę kierunku mapy. Na przykład kierowca samochodu często obraca mapę drogową, aby dopasować ją do kierunku jazdy, a turyści korzystający z mapy i kompasu zwykle orientują mapę tak, aby pionowa linia 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 nadiru (kierunku skierowanego bezpośrednio pod kamerę). Wartość 0 odpowiada kamerze skierowanej prosto w dół. Wartości większe od 0 odpowiadają kamerze skierowanej w stronę horyzontu o określoną liczbę stopni. Gdy zmienisz kąt widzenia, mapa będzie wyświetlana w perspektywie, w której odległe obiekty są mniejsze, a pobliskie – większe. Ilustrują to poniższe przykłady.
Na obrazach poniżej kąt widzenia wynosi 0 stopni. Pierwszy obraz przedstawia schemat tej sytuacji. Pozycja 1 to pozycja kamery, a pozycja 2 to bieżąca pozycja na mapie. Wynikowa mapa jest widoczna poniżej.
|
|
Na obrazach poniżej kąt widzenia wynosi 45 stopni. Zwróć uwagę, że kamera przesuwa się w połowie łuku między pozycją bezpośrednio nad głową (0 stopni) a ziemią (90 stopni), aby zająć pozycję 3. Kamera nadal jest skierowana na środek mapy, ale widoczny jest teraz obszar reprezentowany przez linię w pozycji 4.
|
|
Mapa na tym zrzucie ekranu jest nadal wyśrodkowana w tym samym punkcie co na oryginalnej mapie, ale u góry pojawiło się więcej elementów. Gdy zwiększysz kąt powyżej 45 stopni, obiekty między kamerą a pozycją na mapie będą proporcjonalnie większe, a obiekty za pozycją na mapie będą proporcjonalnie mniejsze, co da efekt trójwymiarowy.
Zoom
Poziom powiększenia kamery określa skalę mapy. Przy większym powiększeniu na ekranie widać więcej szczegółów, a przy mniejszym – większy obszar. Przy poziomie powiększenia 0 skala mapy jest taka, że cały świat ma szerokość około 256 dp (pikseli niezależnych od gęstości).
Zwiększenie poziomu powiększenia o 1 punkt powoduje podwojenie szerokości świata na ekranie. Dlatego na poziomie powiększenia N szerokość świata wynosi w przybliżeniu 256 * 2N dp. Na przykład przy poziomie powiększenia 2 cały świat ma szerokość około 1024 dp.
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 miejsca docelowego, 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 poziomem powiększenia. 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 Google umożliwia zmianę części świata widocznej na mapie. Możesz to zrobić, zmieniając położenie kamery (a nie przesuwając mapę).
Gdy zmienisz kamerę, możesz animować wynikowy 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ć, gdzie chcesz ją przenieść, używając CameraUpdate. Interfejs API Map Google umożliwia tworzenie wielu różnych typów CameraUpdate za pomocą CameraUpdateFactory. Dostępne są te ustawienia:
Zmiana 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
wszystkie inne właściwości bez zmian.
CameraUpdateFactory.zoomTo(float)
zapewnia CameraUpdate, który zmienia poziom powiększenia na podaną wartość,
zachowując wszystkie inne właściwości bez zmian.
CameraUpdateFactory.zoomBy(float) i CameraUpdateFactory.zoomBy(float, Point)
dają Ci CameraUpdate, które zwiększa (lub zmniejsza, jeśli wartość jest ujemna) poziom powiększenia o podaną wartość. Ta druga opcja ustala dany punkt na ekranie tak, aby pozostawał w tym samym miejscu (szerokość i długość geograficzna), i może zmienić położenie kamery, aby to osiągnąć.
Może się okazać, że warto ustawić preferowany minimalny lub maksymalny poziom powiększenia. Jest to 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 kafelkowej 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ą kwestie techniczne, które mogą uniemożliwić interfejsowi API zbyt duże lub zbyt małe powiększenie. Na przykład widok satelitarny lub terenowy może mieć mniejsze maksymalne powiększenie niż kafelki mapy bazowej.
Zmiana pozycji kamery
Istnieją dwie wygodne metody zmian wspólnych pozycji.
CameraUpdateFactory.newLatLng(LatLng) daje Ci CameraUpdate, który zmienia szerokość i długość geograficzną kamery, zachowując jednocześnie wszystkie inne właściwości.
CameraUpdateFactory.newLatLngZoom(LatLng, float)
zapewnia CameraUpdate, który zmienia szerokość i długość geograficzną oraz powiększenie kamery, zachowując wszystkie inne właściwości.
Aby uzyskać pełną elastyczność zmiany położenia kamery, użyj polecenia CameraUpdateFactory.newCameraPosition(CameraPosition), które spowoduje przesunięcie kamery do określonej pozycji za pomocą polecenia CameraUpdate. CameraPosition można uzyskać bezpośrednio, używając new CameraPosition() lub za pomocą CameraPosition.Builder używając new CameraPosition.Builder().
Przesuwanie (przewijanie)
CameraUpdateFactory.scrollBy(float, float) generuje CameraUpdate, który zmienia szerokość i długość geograficzną 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ół, dzięki czemu mapa wydaje się przesunięta w górę. Z kolei ujemne wartości x powodują, że kamera przesuwa się w lewo, przez co mapa wydaje się przesuwać w prawo, a ujemne wartości y powodują, że kamera przesuwa się w górę. Przewijanie odbywa się względem aktualnej orientacji kamery. Na przykład, jeśli azymut kamery wynosi 90 stopni, to wschód jest „na górze”.
Ustanawianie granic
Wyznaczanie granic mapy
Czasami warto przesunąć kamerę tak, aby cały interesujący nas obszar był widoczny przy największym możliwym powiększeniu. Na przykład, jeśli wyświetlasz wszystkie stacje benzynowe w promieniu pięciu mil od aktualnej pozycji użytkownika, możesz przesunąć kamerę tak, aby wszystkie były widoczne na ekranie. Aby to zrobić, najpierw oblicz LatLngBounds, które ma być widoczne na ekranie. Następnie możesz użyć CameraUpdateFactory.newLatLngBounds(LatLngBounds bounds, int
padding), aby uzyskać CameraUpdate zmieniający położenie kamery w taki sposób, aby podany LatLngBounds w całości mieścił się na mapie, biorąc pod uwagę określone wypełnienie (w pikselach). Zwrócony CameraUpdate zapewnia, że odstęp (w pikselach) między podanymi granicami a krawędzią mapy będzie co najmniej równy określonemu wypełnieniu. Pamiętaj, że nachylenie i kierunek mapy będą wynosić 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));
Centrowanie mapy w obrębie obszaru
W niektórych przypadkach możesz chcieć wyśrodkować kamerę w określonych granicach zamiast uwzględniać skrajne krawędzie. Na przykład aby wyśrodkować widok kamery na kraj, zachowując stałe powiększenie. W takim przypadku możesz użyć podobnej metody, tworząc LatLngBounds i używając CameraUpdateFactory.newLatLngZoom(LatLng latLng, float zoom) z LatLngBounds.getCenter(). Metoda getCenter() zwróci środek geograficzny obiektu 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 umieszczony tak, aby jego środek pokrywał się ze środkiem widoku mapy (jeśli podane wymiary są takie same jak wymiary widoku mapy, prostokąt pokrywa się z widokiem mapy). Zwrócony CameraUpdate przesunie kamerę tak, aby określone LatLngBounds były wyśrodkowane na ekranie w danym prostokącie przy największym możliwym poziomie powiększenia, z uwzględnieniem wymaganego dopełnienia.
Uwaga: używaj prostszej metodynewLatLngBounds(boundary, padding) do generowania CameraUpdate tylko wtedy, gdy ma ona służyć do przesuwania kamery po ułożeniu mapy. Podczas układu interfejs API oblicza granice wyświetlania mapy, które są potrzebne do prawidłowego rzutowania ramki ograniczającej. Dla porównania, możesz użyć wartości CameraUpdate zwróconej przez bardziej złożoną metodę newLatLngBounds(boundary, width, height, padding) w dowolnym momencie, nawet zanim mapa zostanie ułożona, ponieważ interfejs API oblicza granice wyświetlania na podstawie przekazanych argumentów.
Ograniczanie możliwości przesuwania widoku przez użytkownika do określonego obszaru
W powyższych scenariuszach ustalasz granice mapy, ale użytkownik może przewijać lub przesuwać obraz poza te granice. Zamiast tego możesz ograniczyć granice środka współrzędnych geograficznych punktu centralnego mapy (punktu docelowego kamery), aby użytkownicy mogli przewijać i przesuwać mapę tylko w tych granicach. Na przykład aplikacja detaliczna dla centrum handlowego lub lotniska może ograniczać mapę do określonych granic, umożliwiając użytkownikom przewijanie i przesuwanie jej w obrębie tych granic.
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);
Poniższy diagram ilustruje sytuację, w której cel kamery jest ograniczony do obszaru nieco większego niż widoczny obszar. Użytkownik może przewijać i przesuwać widok, o ile cel kamery pozostaje w ograniczonym obszarze. Krzyżyk oznacza cel kamery:
Mapa zawsze wypełnia widoczny obszar, nawet jeśli powoduje to wyświetlanie obszarów znajdujących się poza zdefiniowanymi granicami. Jeśli na przykład umieścisz cel kamery w rogu ograniczonego obszaru, obszar za rogiem będzie widoczny w obszarze wyświetlania, ale użytkownicy nie będą mogli przewinąć go dalej. Poniższy diagram ilustruje ten scenariusz. Krzyżyk oznacza cel kamery:
Na poniższym diagramie cel kamery ma bardzo ograniczone granice, co daje użytkownikowi bardzo małą możliwość przewijania lub przesuwania mapy. Krzyżyk reprezentuje cel kamery:
Aktualizowanie widoku z kamery
Aby zastosować CameraUpdate do mapy, możesz natychmiast przesunąć kamerę lub płynnie ją animować. Aby natychmiast przesunąć kamerę o podaną wartość 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, animując zmianę. Aby to zrobić, zamiast dzwonić, kliknij GoogleMap.moveCamera
zadzwoń pod numer GoogleMap.animateCamera.
Mapa płynnie przesunie się do nowych atrybutów. Najbardziej szczegółowa forma tej metody, GoogleMap.animateCamera(cameraUpdate, duration, callback), ma 3 argumenty:
cameraUpdateCameraUpdateopisujący, gdzie przesunąć kamerę.callback- Obiekt, który implementuje interfejs
GoogleMap.CancellableCallback. Ten uogólniony interfejs do obsługi zadań definiuje 2 metody: `onCancel()` i `onFinished()`. W przypadku animacji metody te są wywoływane w tych okolicznościach:onFinish()- Wywoływana, gdy animacja zostanie ukończona bez przerwy.
onCancel()-
Wywoływana, gdy animacja zostanie przerwana przez wywołanie
stopAnimation()lub rozpoczęcie nowego ruchu kamery.Może się tak też zdarzyć, jeśli zadzwonisz pod numer
GoogleMap.stopAnimation().
duration- Pożądany czas trwania animacji w milisekundach jako
int.
Poniższe fragmenty kodu ilustrują niektóre z najczęstszych sposobów przesuwania 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));