Componente Place Markers

El componente Place Markers te permite crear anotaciones de mapa personalizables que muestran información clave de lugares directamente en el mapa. Puedes mostrar contenido como la calificación de un lugar, el tipo de lugar, el estado de abierto o cerrado, el intervalo de precios o texto personalizado (por ejemplo, una etiqueta generada por IA o un número de itinerario). Esto les brinda a los usuarios una experiencia de exploración del mapa más informativa sin necesidad de presionar una tarjeta de lugar detallada.

Íconos y texto disponibles para los marcadores de lugar

Puedes mostrar un ícono de marcador y texto de marcador opcional por cada PlaceMarker.

Los íconos disponibles son los siguientes:

  • Type: Es el tipo de lugar.
  • None: Sin ícono.
Los marcadores de texto disponibles son los siguientes:
  • Rating: Puntuación de calificación.
  • PriceRange: Intervalo de precios (por ejemplo, USD 10 a 20).
  • OpenStatus: Indica si una empresa está abierta o cerrada.
  • Custom: Texto personalizado (por ejemplo, "POPULAR").

Haz referencia al lugar con un ID de lugar (PlaceId), un nombre de recurso (ResourceName) o coordenadas geográficas (Coordinates).

Requisitos de visualización y atribución

Cuando se muestran los marcadores de mapa del kit de IU de Places, estos no deben aparecer de forma aislada. Deben ser interactivos y abrir un componente o una Lightbox de Place Details asociados cuando se haga clic o se presione para proporcionar la marca de Google requerida, la atribución del colaborador y los flujos de Report a Problem.

Consulta nuestros requisitos de atribución de fotos y opiniones para situaciones en las que el espacio es limitado.

Ejemplos de Place Marker

Proporcionamos funciones de @Composable de Jetpack Compose para eliminar la sobrecarga del wrapper de View a Compose y evitar problemas de discrepancia de temas.

Personalizaciones básicas de los marcadores

En el siguiente ejemplo de código, se muestran personalizaciones básicas de marcadores de lugar, como ocultar el pico triangular del bocadillo del marcador predeterminado.

Kotlin

import androidx.compose.runtime.Composable
import com.google.android.libraries.places.compose.PlaceMarker
import com.google.android.libraries.places.compose.marker.MarkerIcon
import com.google.android.libraries.places.compose.marker.MarkerText
import com.google.android.libraries.places.compose.PlaceReference

@Composable
fun DefaultMarker() {
    PlaceMarker(
        reference = PlaceReference.PlaceId("PLACE_ID"),
        icon = MarkerIcon.None,
        beakPresence = false, // remove beak
    )
}

@Composable
fun RatingMarker() {
    PlaceMarker(
        reference = PlaceReference.PlaceId("PLACE_ID"),
        icon = MarkerIcon.None,
        text = MarkerText.Rating
    )
}

@Composable
fun TypeAndRatingMarker() {
    PlaceMarker(
        reference = PlaceReference.PlaceId("PLACE_ID"),
        icon = MarkerIcon.Type,
        text = MarkerText.Rating

    )
}

@Composable
fun PriceRangeMarker() {
    PlaceMarker(
        reference = PlaceReference.ResourceName("places/PLACE_RESOURCE_NAME"),
        icon = MarkerIcon.None,
        text = MarkerText.PriceRange
    )
}

@Composable
fun OpenStatusMarker() {
   PlaceMarker(
       reference = PlaceReference.Coordinates(latitude = 37.7749, longitude = -122.4194),
        icon = MarkerIcon.None,
        text = MarkerText.OpenStatus
   )
}

@Composable
fun CustomTextMarker() {
    PlaceMarker(
        reference = PlaceReference.PlaceId("PLACE_ID"),
        icon = MarkerIcon.None,
        // Custom text accepts a String to display a number (e.g. "3") or text (e.g. "NEW")
        text = MarkerText.Custom("NEW")
    )
}

Crea un objeto de escucha de clics

Puedes proporcionar una devolución de llamada onClick para activar acciones personalizadas cuando se presiona un marcador independiente. Sin embargo, cuando el marcador se renderiza en un mapa (por ejemplo, dentro de un MarkerComposable), el mapa intercepta los eventos de presión. En este caso, debes usar el controlador onClick del MarkerComposable en lugar del del marcador.

En el siguiente ejemplo de código, se muestra cómo usar el controlador onClick de MarkerComposable.

Kotlin

import android.util.Log
import androidx.compose.runtime.Composable
import com.google.android.libraries.places.compose.PlaceMarker
import com.google.android.libraries.places.compose.marker.MarkerIcon
import com.google.android.libraries.places.compose.PlaceReference


/**
 * PlaceMarker used outside of a map (e.g. in a list, bottom sheet, or custom overlay).
 *
 * There is no host component that provides a default click behavior here, so PlaceMarker's own
 * `onClick` is the only way for a developer to react to a tap. This is why `onClick` must stay
 * on the PlaceMarker API.
 */
@Composable
fun ClickableMarkerWithCustomConfig() {
   PlaceMarker(
       reference = PlaceReference.PlaceId("PLACE_ID"),
       icon = MarkerIcon.Type,
       
       onClick = { place ->
           openPlaceCard(place.id) // developer might want to open the place card
           Log.i("PlacesMarker", "Marker was tapped by user!")
       }
   )
}

/**
 * PlaceMarker used as the content of a MarkerComposable on a GoogleMap.
 *
 * MarkerComposable does NOT add PlaceMarker to the touch-input hierarchy: it snapshots the
 * composable into a bitmap and hands that bitmap to the Maps renderer as the marker icon. The
 * rendered marker is a map object, not a Compose node, so:
 *
 *   - PlaceMarker's own `onClick` would never be invoked here (no touch events ever reach it).
 *   - The tap is delivered by the Maps SDK to MarkerComposable's `onClick`, which is the only
 *     click entry point on a map.
 *
 * Accordingly, the state-based `PlaceMarker(state = ...)` overload used below deliberately does
 * not expose an `onClick` parameter, so the correct handler is the only one available.
 */
@Composable
fun PlaceMarkerOnMap(markerState: PlaceMarkerState) {
  GoogleMap(
    modifier = Modifier.fillMaxSize(),
    cameraPositionState = rememberCameraPositionState(),
  ) {
    markerState.location?.let { position ->
      MarkerComposable(
        state = rememberUpdatedMarkerState(position = position),
        // this is the click handler for the map use case.
        onClick = {
          markerState.place?.let { place -> openPlaceCard(place.id) }
          true // consume the event
        },
      ) {
        PlaceMarker(state = markerState)
      }
    }
  }
}

Cómo controlar el estado de carga y las devoluciones de llamada

En el siguiente ejemplo de código, se muestra cómo proporcionar devoluciones de llamada para controlar errores de renderización o de falta de datos.

Kotlin

import android.util.Log
import androidx.compose.runtime.Composable
import com.google.android.libraries.places.compose.PlaceMarker
import com.google.android.libraries.places.compose.marker.MarkerIcon
import com.google.android.libraries.places.compose.PlaceReference

@Composable
fun StatusHandlingMarker() {
    PlaceMarker(
        reference = PlaceReference.PlaceId("PLACE_ID"),
        icon = MarkerIcon.Type,
        // Triggered when attribute data is successfully fetched and the marker is rendered.
        // Returns a minimal Place object with ID, location (LatLng), and viewport fields set.
        onMarkerLoaded = { place ->
            Log.i("PlacesMarker", "Marker successfully loaded for place ID: ${place.id}")
        },
        // Triggered when data fetching fails or required attribute data is missing for the place.
        // Returns an optional Place object and an Exception describing the root cause.
        onMarkerLoadFailed = { place, exception ->
            Log.e("PlacesMarker", "Failed to load marker for place ID: ${place?.id}", exception)
        }
    )
}

Usa PlaceMarkerState para colocar marcadores en el mapa

El objeto Place se devuelve con la ubicación y el viewport para ayudarte a decidir dónde colocar el marcador.

Kotlin

// Step 1: Obtain configured handle in a single 1-line call (PlaceMarker mounted internally)
val markerState = rememberPlaceMarkerState(
  reference = PlaceReference.PlaceId(placeId),
  icon = MarkerIcon.Type
)

// Step 2: Pass PlaceMarkerState.location and PlaceMarker(state = PlaceMarkerState) directly to the map marker
GoogleMap(...) {
  markerState.location?.let { position ->
    MarkerComposable(
      state = rememberMarkerState(position = position),
      onClick = {
        markerState.place?.let { place ->
          // Handle marker click
        }
        true
      }
    ) {
      PlaceMarker(state = markerState) // Render marker UI content directly on map canvas
    }
  }
}

Cómo ajustar el tamaño de un marcador a un tamaño personalizado

Kotlin

// Off the map: scale with a one-line modifier.
// Modifier.scale is a draw-time transform, so the bubble, beak, icon and text all scale together.
@Composable
fun ScaledMarker() {
  PlaceMarker(
    reference = PlaceReference.PlaceId(placeId),
    icon = MarkerIcon.Type,
    text = MarkerText.Rating,
    modifier = Modifier.scale(2.1f),
  )
}

// On the map: scale by overriding LocalDensity.
// MarkerComposable snapshots its content into a marker bitmap sized to the measured layout bounds.
// Modifier.scale does not change those bounds, so the marker would be clipped and blurry. Scaling
// the density re-measures every dp and sp inside the marker, so the bitmap, the layout bounds and
// the map hit target all grow with it.
@Composable
fun ScaledMarkerOnMap(markerState: PlaceMarkerState) {
  val density = LocalDensity.current
  val scaledDensity = remember(density) {
    Density(density = density.density * 2.1f, fontScale = density.fontScale * 2.1f)
  }
  GoogleMap(...) {
    markerState.location?.let { position ->
      MarkerComposable(
        state = rememberUpdatedMarkerState(position = position),
        anchor = Offset(0.5f, 1.0f),
      ) {
        CompositionLocalProvider(LocalDensity provides scaledDensity) {
          PlaceMarker(state = markerState)
        }
      }
    }
  }
}