Znaczniki

Wybierz platformę: Android iOS JavaScript

Znaczniki wskazują pojedyncze lokalizacje na mapie. Znaczniki możesz dostosowywać, zmieniając domyślny kolor lub zastępując ikonę znacznika własnym obrazem. Okna informacyjne mogą stanowić dodatkowy kontekst dla znacznika.

Przykładowe fragmenty kodu

W repozytorium APIDemos na GitHubie jest przykład, który przedstawia różne funkcje znaczników:

Kotlin

Java

Wstęp

Znaczniki określają lokalizacje na mapie. Domyślny znacznik używa standardowej ikony, która jest zgodna z wyglądem i stylem Map Google. Kolor ikony, obraz lub punkt zakotwiczenia można zmienić za pomocą interfejsu API. Znaczniki to obiekty typu Marker, które są dodawane do mapy za pomocą metody GoogleMap.addMarker(markerOptions).

Znaczniki są interaktywne. Domyślnie odbierają zdarzenia click i często są używane razem z detektorami zdarzeń do wyświetlania okien informacyjnych. Ustawienie właściwości draggable znacznika na true umożliwia użytkownikowi zmianę jego pozycji. Przytrzymaj znacznik, aby włączyć możliwość przenoszenia znacznika.

Domyślnie, gdy użytkownik kliknie znacznik, w prawym dolnym rogu mapy pojawi się pasek narzędzi mapy, dając mu szybki dostęp do aplikacji mobilnej Mapy Google. Pasek narzędzi możesz wyłączyć. Więcej informacji znajdziesz w przewodniku po ustawieniach.

Pierwsze kroki ze znacznikami

W tym odcinku Map na żywo omawiamy podstawy dodawania znaczników do mapy za pomocą pakietu SDK Map Google na Androida.

Dodaj znacznik

Poniższy przykład pokazuje, jak dodać znacznik do mapy. Znacznik jest tworzony w miejscu współrzędnych -33.852,151.211 (Sydney, Australia) i po kliknięciu wyświetla ciąg „Marker in Sydney” (Marker w Sydney).

Kotlin



override fun onMapReady(googleMap: GoogleMap) {
    // Add a marker in Sydney, Australia,
    // and move the map's camera to the same location.
    val sydney = LatLng(-33.852, 151.211)
    googleMap.addMarker(
        MarkerOptions()
            .position(sydney)
            .title("Marker in Sydney")
    )
    googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
}

      

Java


@Override
public void onMapReady(GoogleMap googleMap) {
    // Add a marker in Sydney, Australia,
    // and move the map's camera to the same location.
    LatLng sydney = new LatLng(-33.852, 151.211);
    googleMap.addMarker(new MarkerOptions()
        .position(sydney)
        .title("Marker in Sydney"));
    googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}

      

Wyświetl dodatkowe informacje o znacznika

Częstym wymaganiem jest wyświetlanie dodatkowych informacji o miejscu lub lokalizacji, gdy użytkownik kliknie znacznik na mapie. Zobacz przewodnik po oknach informacyjnych.

Powiąż dane ze znacznikiem

Dowolny obiekt danych możesz przechowywać za pomocą znacznika za pomocą funkcji Marker.setTag(), a obiekt danych możesz pobrać za pomocą metody Marker.getTag(). Poniższy przykład pokazuje, jak za pomocą tagów liczyć liczbę kliknięć znacznika:

Kotlin



/**
 * A demo class that stores and retrieves data objects with each marker.
 */
class MarkerDemoActivity : AppCompatActivity(),
    OnMarkerClickListener, OnMapReadyCallback {
    private val PERTH = LatLng(-31.952854, 115.857342)
    private val SYDNEY = LatLng(-33.87365, 151.20689)
    private val BRISBANE = LatLng(-27.47093, 153.0235)

    private var markerPerth: Marker? = null
    private var markerSydney: Marker? = null
    private var markerBrisbane: Marker? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_markers)
        val mapFragment =
            supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
        mapFragment!!.getMapAsync(this)
    }

    /** Called when the map is ready.  */
    override fun onMapReady(map: GoogleMap) {
        // Add some markers to the map, and add a data object to each marker.
        markerPerth = map.addMarker(
            MarkerOptions()
                .position(PERTH)
                .title("Perth")
        )
        markerPerth?.tag = 0
        markerSydney = map.addMarker(
            MarkerOptions()
                .position(SYDNEY)
                .title("Sydney")
        )
        markerSydney?.tag = 0
        markerBrisbane = map.addMarker(
            MarkerOptions()
                .position(BRISBANE)
                .title("Brisbane")
        )
        markerBrisbane?.tag = 0

        // Set a listener for marker click.
        map.setOnMarkerClickListener(this)
    }

    /** Called when the user clicks a marker.  */
    override fun onMarkerClick(marker: Marker): Boolean {

        // Retrieve the data from the marker.
        val clickCount = marker.tag as? Int

        // Check if a click count was set, then display the click count.
        clickCount?.let {
            val newClickCount = it + 1
            marker.tag = newClickCount
            Toast.makeText(
                this,
                "${marker.title} has been clicked $newClickCount times.",
                Toast.LENGTH_SHORT
            ).show()
        }

        // Return false to indicate that we have not consumed the event and that we wish
        // for the default behavior to occur (which is for the camera to move such that the
        // marker is centered and for the marker's info window to open, if it has one).
        return false
    }
}

      

Java


/**
 * A demo class that stores and retrieves data objects with each marker.
 */
public class MarkerDemoActivity extends AppCompatActivity implements
    GoogleMap.OnMarkerClickListener,
    OnMapReadyCallback {

    private final LatLng PERTH = new LatLng(-31.952854, 115.857342);
    private final LatLng SYDNEY = new LatLng(-33.87365, 151.20689);
    private final LatLng BRISBANE = new LatLng(-27.47093, 153.0235);

    private Marker markerPerth;
    private Marker markerSydney;
    private Marker markerBrisbane;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_markers);
        SupportMapFragment mapFragment =
            (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    /** Called when the map is ready. */
    @Override
    public void onMapReady(GoogleMap map) {
        // Add some markers to the map, and add a data object to each marker.
        markerPerth = map.addMarker(new MarkerOptions()
            .position(PERTH)
            .title("Perth"));
        markerPerth.setTag(0);

        markerSydney = map.addMarker(new MarkerOptions()
            .position(SYDNEY)
            .title("Sydney"));
        markerSydney.setTag(0);

        markerBrisbane = map.addMarker(new MarkerOptions()
            .position(BRISBANE)
            .title("Brisbane"));
        markerBrisbane.setTag(0);

        // Set a listener for marker click.
        map.setOnMarkerClickListener(this);
    }

    /** Called when the user clicks a marker. */
    @Override
    public boolean onMarkerClick(final Marker marker) {

        // Retrieve the data from the marker.
        Integer clickCount = (Integer) marker.getTag();

        // Check if a click count was set, then display the click count.
        if (clickCount != null) {
            clickCount = clickCount + 1;
            marker.setTag(clickCount);
            Toast.makeText(this,
                marker.getTitle() +
                    " has been clicked " + clickCount + " times.",
                Toast.LENGTH_SHORT).show();
        }

        // Return false to indicate that we have not consumed the event and that we wish
        // for the default behavior to occur (which is for the camera to move such that the
        // marker is centered and for the marker's info window to open, if it has one).
        return false;
    }
}

      

Oto kilka przykładów sytuacji, w których warto przechowywać i pobierać dane za pomocą znaczników:

  • Twoja aplikacja może obsługiwać różne typy znaczników i chcesz, aby były traktowane inaczej, gdy użytkownik je kliknie. Aby to zrobić, możesz zapisać właściwość String ze znacznikiem wskazującym typ.
  • Być może korzystasz z systemu, który ma unikalne identyfikatory rekordów, gdzie znaczniki reprezentują konkretne rekordy w tym systemie.
  • Dane znacznika mogą wskazywać priorytet, który ma być stosowany przy określaniu kolejności nakładania znacznika.

Dodawanie znacznika do przeciągania

Po dodaniu znacznika do mapy możesz zmienić jego położenie, o ile jego właściwość draggable ma wartość true. Przytrzymaj znacznik, aby włączyć przeciąganie. Gdy usuniesz palec z ekranu, znacznik pozostanie w tym miejscu.

Domyślnie znaczników nie można przeciągać. Musisz wyraźnie ustawić znacznik, aby można go było przeciągnąć za pomocą funkcji MarkerOptions.draggable(boolean) przed dodaniem go do mapy lub Marker.setDraggable(boolean), gdy zostanie on dodany do mapy. Możesz nasłuchiwać zdarzeń przeciągania w znaczniku, tak jak to opisano w sekcji Zdarzenia przeciągania za pomocą znacznika.

Poniższy fragment kodu dodaje ruchomy znacznik w Perth w Australii.

Kotlin



val perthLocation = LatLng(-31.90, 115.86)
val perth = map.addMarker(
    MarkerOptions()
        .position(perthLocation)
        .draggable(true)
)

      

Java


final LatLng perthLocation = new LatLng(-31.90, 115.86);
Marker perth = map.addMarker(
    new MarkerOptions()
        .position(perthLocation)
        .draggable(true));

      

Dostosowywanie znacznika

Ten film pokazuje, jak używać znaczników do wizualizacji lokalizacji na mapie.

Znaczniki mogą wskazywać niestandardowy obraz wyświetlany w miejscu ikony domyślnej. Zdefiniowanie ikony wymaga skonfigurowania kilku właściwości mających wpływ na wizualne zachowanie znacznika.

Znaczniki obsługują dostosowywanie za pomocą tych właściwości:

Pozycja (wymagana)
Wartość LatLng określająca pozycję znacznika na mapie. Jest to jedyna wymagana właściwość obiektu Marker.
Kotwica
Punkt na obrazie, który zostanie umieszczony w pozycji położenia geograficznego znacznika. Domyślnie jest to środek dolnej części obrazu.
Alfa
Ustawia przezroczystość znacznika. Domyślna wartość to 1,0.
Tytuł
Ciąg tekstowy wyświetlany w oknie informacyjnym, gdy użytkownik kliknie znacznik.
Krótki opis
Dodatkowy tekst wyświetlany pod tytułem.
Ikona
Bitmapa wyświetlana zamiast domyślnego obrazu znacznika.
Do przeciągania
Ustaw wartość true, jeśli chcesz zezwolić użytkownikowi na przenoszenie znacznika. Domyślna wartość to false.
Widoczne
Ustaw wartość false, aby znacznik był niewidoczny. Wartość domyślna to true.
Orientacja płaska lub billboardu
Domyślnie znaczniki mają orientację billboardu, co oznacza, że są rysowane względem ekranu urządzenia, a nie powierzchni mapy. Obracanie, przechylanie lub powiększanie mapy nie zmienia orientacji znacznika. Możesz ustawić położenie znacznika tak, aby znajdowało się płasko względem Ziemi. Płaskie znaczniki obracają się, gdy mapa jest obrócona, i zmieniają perspektywę, gdy jest ona przechylona. Podobnie jak w przypadku znaczników billboardów, płaskie znaczniki zachowują swój rozmiar po powiększeniu lub pomniejszeniu mapy.
Rotacja
Orientacja znacznika podana w stopniach w prawo. Położenie znacznika zmienia się domyślnie, jeśli jest on płaski. Domyślnym położeniem płaskiego znacznika jest wyrównany północ. Jeśli znacznik nie jest płaski, domyślnie jest skierowany w górę, a obrót odbywa się w taki sposób, że jest on zawsze skierowany w stronę kamery.

Poniższy fragment kodu tworzy prosty znacznik z ikoną domyślną.

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(
    new MarkerOptions()
        .position(melbourneLocation));

      

Dostosuj kolor znacznika

Kolor domyślnego obrazu znacznika można dostosować, przekazując obiekt BitmapDescriptor do metody icon(). Możesz użyć zestawu wstępnie zdefiniowanych kolorów w obiekcie BitmapDescriptorFactory lub ustawić niestandardowy kolor znacznika za pomocą metody BitmapDescriptorFactory.defaultMarker(float hue). Barwa ma wartość z zakresu od 0 do 360 i reprezentuje punkty na kołach kolorów.

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(
    new MarkerOptions()
        .position(melbourneLocation)
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));

      

Dostosowywanie przezroczystości znacznika

Przezroczystość znacznika można kontrolować za pomocą metody MarkOptions.alpha(). Wartość alfa należy określić jako liczbę zmiennoprzecinkową z zakresu od 0,0 do 1,0, gdzie 0 oznacza pełną przezroczystość, a 1 – całkowitą nieprzejrzystość.

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
        .alpha(0.7f)
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(new MarkerOptions()
    .position(melbourneLocation)
    .alpha(0.7f));

      

Dostosuj obraz znacznika

Domyślny znacznik możesz zastąpić niestandardowym obrazem znacznika, często nazywanym ikoną. Ikony niestandardowe są zawsze ustawione jako BitmapDescriptor i definiowane za pomocą jednej z metod klasy BitmapDescriptorFactory.

fromAsset(String assetName)
Tworzy niestandardowy znacznik z nazwą obrazu bitmapy, który znajduje się w katalogu zasobów.
fromBitmap(Bitmap image)
Tworzy niestandardowy znacznik na podstawie obrazu bitmapy.
fromFile(String fileName)
Tworzy ikonę niestandardową o nazwie pliku mapy bitowej znajdującej się w pamięci wewnętrznej.
fromPath(String absolutePath)
Tworzy znacznik niestandardowy na podstawie bezwzględnej ścieżki pliku obrazu bitmapy.
fromResource(int resourceId)
Tworzy niestandardowy znacznik z użyciem identyfikatora zasobu obrazu bitmapy.

Poniższy fragment kodu tworzy znacznik z niestandardową ikoną.

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
        .title("Melbourne")
        .snippet("Population: 4,137,400")
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow))
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(
    new MarkerOptions()
        .position(melbourneLocation)
        .title("Melbourne")
        .snippet("Population: 4,137,400")
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow)));

      

Spłaszcz znacznik

Ikony znacznika są zwykle rysowane względem ekranu. Obracanie, pochylanie lub powiększanie mapy nie zmienia orientacji znacznika. Możesz ustawić położenie znacznika tak, aby znajdowało się płasko względem Ziemi. Znaczniki ustawione w ten sposób będą obracać się, gdy mapa zostanie obrócona, i zmienić perspektywę, gdy mapa jest przechylona. Płaskie znaczniki zachowują swój rozmiar przy powiększaniu lub pomniejszaniu mapy.

Aby zmienić orientację znacznika, ustaw jego właściwość flat na true.

Kotlin



val perthLocation = LatLng(-31.90, 115.86)
val perth = map.addMarker(
    MarkerOptions()
        .position(perthLocation)
        .flat(true)
)

      

Java


final LatLng perthLocation = new LatLng(-31.90, 115.86);
Marker perth = map.addMarker(
    new MarkerOptions()
        .position(perthLocation)
        .flat(true));

      

Obracanie znacznika

Marker pozwala obracać znacznik wokół punktu zakotwiczenia.setRotation(). Obrót jest mierzony w stopniach w prawo od pozycji domyślnej. Jeśli znacznik jest płasko na mapie, domyślną wartością jest północ. Jeśli znacznik nie jest płaski, domyślnie jest skierowany w górę, a obrót odbywa się w taki sposób, że jest on zawsze skierowany w stronę kamery.

Poniższy przykład obraca znacznik o 90°. Ustawienie punktu zakotwiczenia na 0.5,0.5 powoduje obrócenie znacznika wokół jego środka, a nie podstawy.

Kotlin



val perthLocation = LatLng(-31.90, 115.86)
val perth = map.addMarker(
    MarkerOptions()
        .position(perthLocation)
        .anchor(0.5f, 0.5f)
        .rotation(90.0f)
)

      

Java


final LatLng perthLocation = new LatLng(-31.90, 115.86);
Marker perth = map.addMarker(
    new MarkerOptions()
        .position(perthLocation)
        .anchor(0.5f,0.5f)
        .rotation(90.0f));

      

Znacznik kolejności nakładania

Ustawienie kolejności nakładania określa kolejność nakładania tego znacznika w stosunku do innych znaczników na mapie. Znacznik o wysokiej kolejności nakładania elementów jest rysowany nad znacznikami o niższych wartościach. Domyślna wartość kolejności nakładania elementów to 0.

Ustaw kolejność nakładania elementów w obiekcie opcji znacznika, wywołując metodę MarkerOptions.zIndex(), jak pokazano w tym fragmencie kodu:

Kotlin



map.addMarker(
    MarkerOptions()
        .position(LatLng(10.0, 10.0))
        .title("Marker z1")
        .zIndex(1.0f)
)

      

Java


map.addMarker(new MarkerOptions()
    .position(new LatLng(10, 10))
    .title("Marker z1")
    .zIndex(1.0f));

      

Aby uzyskać dostęp do ustawienia kolejności nakładania znacznika, wywołaj polecenie Marker.getZIndex(), a możesz go zmienić, wywołując metodę Marker.setZIndex().

Znaczniki są zawsze rysowane nad warstwami z kafelkami i innymi nakładkami innymi niż znaczniki (nakładki na powierzchni, linie łamane, wielokąty i inne kształty) niezależnie od kolejności nakładania elementów innych nakładek. Znaczniki znajdują się w oddzielnej grupie kolejności nakładania elementów (z-index) w porównaniu z innymi nakładkami.

Więcej informacji o wpływie kolejności nakładania elementów na zdarzenia kliknięcia znajdziesz poniżej.

Obsługa zdarzeń znacznika

Interfejs API Map Google umożliwia wykrywanie zdarzeń związanych ze znacznikami i reagowanie na nie. Aby nasłuchiwać tych zdarzeń, musisz ustawić odpowiedni detektor w obiekcie GoogleMap, do którego należą znaczniki. Gdy zdarzenie wystąpi w jednym ze znaczników na mapie, wywołanie zwrotne detektora będzie wykonywane z odpowiednim obiektem Marker przekazanym jako parametr. Aby porównać ten obiekt Marker z własnym odwołaniem z obiektem Marker, musisz użyć equals(), a nie ==.

Możesz nasłuchiwać tych zdarzeń:

Zdarzenia kliknięcia znacznika

Do wykrywania zdarzeń kliknięcia znacznika możesz użyć OnMarkerClickListener. Aby ustawić ten detektor na mapie, zadzwoń pod numer GoogleMap.setOnMarkerClickListener(OnMarkerClickListener). Po kliknięciu znacznika przez użytkownika wywoływane jest wywołanie onMarkerClick(Marker), a znacznik zostanie przekazany jako argument. Ta metoda zwraca wartość logiczną, która wskazuje, czy zdarzenie zostało przetworzone (czyli chcesz pominąć działanie domyślne). Jeśli zwróci wartość false, oprócz zachowania niestandardowego pojawi się działanie domyślne. Domyślnym zachowaniem w przypadku kliknięcia znacznika jest wyświetlenie jego okna informacyjnego (jeśli jest dostępne) i przesunięcie kamery tak, aby znacznik znalazł się na środku mapy.

Wpływ kolejności nakładania elementów na zdarzenia kliknięcia:

  • Gdy użytkownik kliknie klaster znaczników, wywoływane jest zdarzenie kliknięcia dla znacznika o najwyższej wartości kolejności nakładania elementów.
  • Na kliknięcie wywoływane jest maksymalnie 1 zdarzenie. Oznacza to, że kliknięcie nie jest przekazywane do znaczników ani innych nakładek o niższych wartościach kolejności nakładania elementów.
  • Kliknięcie zbioru znaczników powoduje, że kolejne kliknięcia są cyklicznie wybierane w klastrze. Kolejność cyklu na początku określa priorytet z-index, a następnie bliskość punktu kliknięcia.
  • Jeśli użytkownik kliknie poza zasięgiem klastra, interfejs API ponownie obliczy klaster i zresetuje stan cyklu kliknięcia, tak aby rozpoczynał się on od początku.
  • Przed ponownym rozpoczęciem cyklu zdarzenie kliknięcia przechodzi przez grupy znaczników do innych kształtów i nakładek.
  • Znaczniki znajdują się w osobnej grupie kolejności nakładania elementów w porównaniu z innymi nakładkami lub kształtami (liniami łamanymi, wielokątami, okręgami i nakładkami na ziemi), niezależnie od tego, czy występują one w pozostałych nakładkach. Jeśli na siebie nakłada się wiele znaczników, nakładek lub kształtów, zdarzenie kliknięcia jest najpierw przetwarzane przez klaster znaczników, a następnie wywoływane dla innych klikalnych nakładek lub kształtów w zależności od ich wartości z-index.

Zdarzenia przeciągania znacznika

Do wykrywania zdarzeń przeciągania znacznika możesz użyć obiektu OnMarkerDragListener. Aby ustawić ten detektor na mapie, zadzwoń pod numer GoogleMap.setOnMarkerDragListener. Aby przeciągnąć znacznik, użytkownik musi go przytrzymać. Gdy użytkownik usunie palec z ekranu, znacznik pozostanie w tym miejscu. Po przeciągnięciu znacznika początkowo wywoływana jest nazwa onMarkerDragStart(Marker). Podczas przeciągania znacznika obiekt onMarkerDrag(Marker) jest wywoływany stale. Na końcu przeciągania jest wywoływana metoda onMarkerDragEnd(Marker). W każdej chwili możesz sprawdzić położenie znacznika, wywołając polecenie Marker.getPosition().