Mapy w pakiecie Maps SDK na Androida można przechylać i obracać za pomocą prostych gestów, co pozwala użytkownikom dostosować mapę do orientacji, która im odpowiada. 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 demonstruje funkcje aparatu:
- CameraDemoActivity – Kotlin: zmiana pozycji kamery
- CameraDemoActivity – Java: zmiana pozycji kamery
Wprowadzenie
Podobnie jak Mapy Google w internecie, pakiet Maps SDK na Androida przedstawia powierzchnię świata (kulę) na ekranie urządzenia (płaskiej powierzchni) za pomocą odwzorowania walcowego równokątnego. W kierunku wschodnim i zachodnim mapa powtarza się w nieskończoność, ponieważ świat płynnie się zapętla. W kierunku północnym i południowym mapa jest ograniczona do około 85 stopni na północ i 85 stopni na południe.
Uwaga: rzutowanie Mercatora ma skończoną szerokość wzdłuż długości geograficznej, ale nieskończoną wysokość wzdłuż szerokości geograficznej. „Odcinamy” zdjęcia mapy podstawowej, korzystając z odwzorowania Merkatora przy około +/- 85 stopniach, aby uzyskać kwadratowy kształt mapy, co ułatwia wybór kafelków.
Pakiet Maps SDK na Androida umożliwia zmianę punktu widzenia użytkownika na mapie przez modyfikację kamery mapy.
Zmiany w ustawieniach kamery nie wpłyną na znaczniki, nakładki ani inne dodane przez Ciebie elementy graficzne, ale możesz je zmodyfikować, aby lepiej pasowały do nowego widoku.
Możesz nasłuchiwać gestów użytkownika na mapie i zmieniać mapę w odpowiedzi na jego żądania. Na przykład metoda wywołania zwrotnego OnMapClickListener.onMapClick() reaguje na pojedyncze kliknięcie mapy. Metoda otrzymuje szerokość i długość geograficzną lokalizacji kliknięcia, więc możesz zareagować, 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 gest przeciągania znacznika.
Możesz też nasłuchiwać ruchów kamery, aby aplikacja otrzymywała powiadomienie, gdy kamera zacznie się poruszać, będzie się poruszać lub przestanie się poruszać. Więcej informacji znajdziesz w przewodniku po zdarzeniach zmiany 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) określają te właściwości: cel (szerokość i długość geograficzna), orientacja, nachylenie i powiększenie.
Cel (lokalizacja)
Cel kamery to lokalizacja środka mapy, określona jako współrzędne szerokości i długości geograficznej.
Szerokość geograficzna może wynosić od –85 do 85 stopni. Wartości spoza tego zakresu są zmieniane na najbliższe wartości graniczne. 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 spoza tego zakresu zostaną zawinięte tak, aby mieściły się w zakresie (-180, 180). Na przykład wartości 480, 840 i 1200 zostaną przekształcone na 120 stopni.Kierunek (orientacja)
Azymut kamery określa kierunek kompasu, mierzony w stopniach od północy geograficznej, odpowiadający górnej krawędzi mapy. Jeśli narysujesz pionową linię od środka mapy do jej górnej krawędzi, kierunek będzie odpowiadał kierunkowi kamery (mierzonemu w stopniach) względem północy geograficznej.
Wartość 0 oznacza, że góra mapy wskazuje północ geograficzną. Wartość 90 oznacza, że góra mapy wskazuje wschód (90 stopni na kompasie). Wartość 180 oznacza, że góra mapy jest skierowana na południe.
Interfejs API Map Google umożliwia zmianę orientacji mapy. Na przykład kierowca często obraca mapę drogową, aby dopasować ją do kierunku jazdy, podczas gdy turyści korzystający z mapy i kompasu zwykle ustawiają mapę tak, aby pionowa linia wskazywała północ.
Przechylenie (kąt widzenia)
Nachylenie określa pozycję kamery na łuku bezpośrednio nad środkiem mapy, mierzoną w stopniach od nadiru (kierunku bezpośrednio pod kamerą). Wartość 0 odpowiada kamerze skierowanej prosto w dół. Wartości większe niż 0 odpowiadają kamerze pochylonej w kierunku horyzontu o określoną liczbę stopni. Gdy zmienisz kąt widzenia, mapa będzie wyświetlana w perspektywie, z mniejszymi obiektami w oddali i większymi obiektami w pobliżu. Ilustracje poniżej pokazują, jak to działa.
Na obrazach poniżej kąt widzenia wynosi 0 stopni. Pierwszy obraz przedstawia schemat tego rozwiązania: pozycja 1 to pozycja kamery, a pozycja 2 to bieżąca pozycja na mapie. Poniżej znajduje się mapa, która powstała w wyniku tego zapytania.
|
|
Na obrazach poniżej kąt widzenia wynosi 45 stopni. Zauważ, że kamera przesuwa się do pozycji 3, czyli do połowy łuku między pozycją bezpośrednio nad głową (0 stopni) a ziemią (90 stopni). Kamera nadal jest skierowana na punkt środkowy mapy, ale obszar reprezentowany przez linię w pozycji 4 jest teraz widoczny.
|
|
Mapa na tym zrzucie ekranu jest nadal wyśrodkowana na tym samym punkcie co oryginalna mapa, ale u góry mapy pojawiło się więcej funkcji. Gdy zwiększysz kąt powyżej 45 stopni, obiekty między kamerą a pozycją na mapie będą wydawać się proporcjonalnie większe, a obiekty poza pozycją na mapie – proporcjonalnie mniejsze, co daje efekt trójwymiarowości.
Zoom
Poziom powiększenia kamery określa skalę mapy. Przy większych poziomach powiększenia na ekranie widać więcej szczegółów, a przy mniejszych – większy obszar świata. Na 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 powoduje podwojenie szerokości świata na ekranie. Dlatego przy poziomie powiększenia N szerokość świata wynosi około 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 przez mapę 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órą może być minimalny lub maksymalny poziom powiększenia. Poniższa lista zawiera przybliżony poziom szczegółowości, którego możesz się spodziewać na każdym poziomie 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żna to zrobić, zmieniając pozycję kamery (a nie przesuwając mapę).
Po zmianie kamery możesz animować jej ruch. 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 pozostałe właściwości bez zmian.
CameraUpdateFactory.zoomTo(float)
zwraca obiekt 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) zwracają obiekt CameraUpdate, który zwiększa (lub zmniejsza, jeśli wartość jest ujemna) poziom powiększenia o podaną wartość. Druga metoda ustala dany punkt na ekranie, tak aby pozostawał w tym samym miejscu (szerokość/długość geograficzna), i może zmienić lokalizację kamery, aby to osiągnąć.
Możesz ustawić preferowany minimalny lub maksymalny poziom powiększenia. Jest to przydatne na przykład do kontrolowania wrażeń użytkownika, jeśli aplikacja pokazuje określony obszar wokół interesującego miejsca lub jeśli używasz niestandardowej nakładki kafelkowej z ograniczonym zestawem poziomów powiększenia.
Kotlin
map.setMinZoomPreference(6.0f) map.setMaxZoomPreference(14.0f)
Java
map.setMinZoomPreference(6.0f); map.setMaxZoomPreference(14.0f);
Pamiętaj, że istnieją kwestie techniczne, które mogą uniemożliwić interfejsowi API umożliwienie użytkownikom zbyt dużego lub zbyt małego powiększenia. Na przykład widok satelitarny lub widok terenu może mieć mniejsze maksymalne powiększenie niż kafelki mapy podstawowej.
Zmienianie pozycji kamery
Dostępne są 2 metody ułatwiające wprowadzanie typowych zmian pozycji.
CameraUpdateFactory.newLatLng(LatLng) zwraca obiekt CameraUpdate, który zmienia szerokość i długość geograficzną kamery, zachowując wszystkie pozostałe właściwości.
CameraUpdateFactory.newLatLngZoom(LatLng, float) zwraca obiekt CameraUpdate, który zmienia szerokość i długość geograficzną oraz powiększenie kamery, zachowując wszystkie pozostałe właściwości.
Aby uzyskać pełną elastyczność w zmianie pozycji kamery, użyj CameraUpdateFactory.newCameraPosition(CameraPosition), co daje CameraUpdate, który przesuwa kamerę do danej pozycji. Obiekt CameraPosition można uzyskać bezpośrednio za pomocą new CameraPosition() lub za pomocą CameraPosition.Builder przy użyciu new CameraPosition.Builder().
Przesuwanie (przewijanie)
CameraUpdateFactory.scrollBy(float, float) zwraca obiekt CameraUpdate, który zmienia szerokość i długość geograficzną kamery, dzięki czemu mapa przesuwa się o określoną liczbę pikseli. Dodatnia wartość x powoduje przesunięcie kamery w prawo, co sprawia, że mapa wydaje się przesunięta w lewo. Dodatnia wartość y powoduje przesunięcie kamery w dół, co sprawia, że 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 powiązane z bieżącą orientacją kamery. Jeśli na przykład kamera ma kąt 90 stopni, wschód jest „w górę”.
Wyznaczanie granic
Ustawianie granic mapy
Czasami warto przesunąć kamerę tak, aby cały interesujący obszar był widoczny przy największym możliwym poziomie powiększenia. Jeśli na przykład wyświetlasz wszystkie stacje benzynowe w promieniu 8 kilometrów od bieżącej pozycji użytkownika, możesz przesunąć kamerę tak, aby wszystkie były widoczne na ekranie. Aby to zrobić, najpierw oblicz LatLngBounds, które chcesz wyświetlać 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, z uwzględnieniem określonego wypełnienia (w pikselach). Zwrócony obiekt CameraUpdate zapewnia, że odstęp (w pikselach) między podanymi granicami a krawędzią mapy będzie co najmniej równy określonemu dopełnieniu. Pamiętaj, że nachylenie i orientacja 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));
Wyśrodkowywanie mapy na obszarze
W niektórych przypadkach możesz chcieć wyśrodkować kamerę w granicach, zamiast uwzględniać skrajne granice. Możesz na przykład wyśrodkować kamerę na kraju, 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() zwraca geograficzny środek elementu 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, które odpowiadają wymiarom mapy. Prostokąt jest umieszczony tak, że jego środek jest taki sam jak środek widoku mapy (jeśli więc podane wymiary są takie same jak wymiary widoku mapy, prostokąt pokrywa się z widokiem mapy). Zwrócony obiekt CameraUpdate przesunie kamerę tak, aby określone współrzędne LatLngBounds były wyśrodkowane na ekranie w danym prostokącie przy największym możliwym poziomie powiększenia, z uwzględnieniem wymaganego wypełnienia.
Uwaga: prostszą metodę newLatLngBounds(boundary, padding) do generowania obiektu CameraUpdate stosuj tylko wtedy, gdy ma on służyć do przesuwania kamery po utworzeniu układu mapy. Podczas układania interfejs API oblicza granice wyświetlania mapy, które są potrzebne do prawidłowego wyświetlenia ramki ograniczającej. Dla porównania: obiektu CameraUpdate zwracanego przez bardziej złożoną metodę newLatLngBounds(boundary, width, height, padding) możesz użyć w dowolnym momencie, nawet przed utworzeniem układu mapy, ponieważ interfejs API oblicza granice wyświetlania na podstawie przekazanych argumentów.
ograniczenie przesuwania mapy przez użytkownika do danego obszaru,
W powyższych scenariuszach ustawiasz granice mapy, ale użytkownik może przewijać lub przesuwać mapę poza te granice. Zamiast tego możesz ograniczyć granice szerokości i długości geograficznej punktu centralnego mapy (celu kamery), aby użytkownicy mogli przewijać i przesuwać tylko w tych granicach. Na przykład aplikacja dla centrum handlowego lub lotniska może ograniczyć 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);
Na poniższym diagramie przedstawiono 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 reprezentuje cel kamery:
Mapa zawsze wypełnia widoczny obszar, nawet jeśli powoduje to wyświetlanie obszarów poza zdefiniowanymi granicami. Jeśli na przykład umieścisz cel kamery w rogu ograniczonego obszaru, obszar poza rogiem będzie widoczny w widocznym obszarze, ale użytkownicy nie będą mogli przewijać dalej w tym obszarze. Ten scenariusz ilustruje poniższy diagram. Krzyżyk reprezentuje cel kamery:
Na poniższym diagramie cel kamery ma bardzo ograniczone granice, co daje użytkownikowi bardzo mało możliwości przewijania lub przesuwania mapy. Krzyżyk reprezentuje cel kamery:
Aktualizowanie widoku kamery
Aby zastosować CameraUpdate na mapie, możesz natychmiast przesunąć kamerę lub płynnie ją animować. Aby natychmiast przesunąć kamerę za pomocą podanego obiektu CameraUpdate, możesz wywołać funkcję GoogleMap.moveCamera(CameraUpdate).
Możesz poprawić wrażenia użytkowników, zwłaszcza w przypadku krótkich ruchów, animując zmianę. Aby to zrobić, zamiast wywoływać funkcję GoogleMap.moveCamera, wywołaj funkcję GoogleMap.animateCamera.
Mapa płynnie przejdzie do nowych atrybutów. Najbardziej szczegółowa forma tej metody, GoogleMap.animateCamera(cameraUpdate, duration, callback), zawiera 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 są wywoływane w tych okolicznościach:onFinish()- Wywoływane, jeśli animacja zostanie ukończona bez przerw.
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 wywołasz funkcję
GoogleMap.stopAnimation().
duration- Żądany czas trwania animacji w milisekundach jako
int.
Poniższe fragmenty kodu pokazują niektóre z typowych 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));