کامپوننت نشانگرهای مکان

کامپوننت نشانگرهای مکان به شما امکان می‌دهد حاشیه‌نویسی‌های نقشه قابل تنظیمی ایجاد کنید که اطلاعات کلیدی مکان را مستقیماً روی نقشه نمایش می‌دهند. می‌توانید محتوایی مانند رتبه‌بندی مکان، نوع مکان، وضعیت باز یا بسته بودن، محدوده قیمت یا متن سفارشی (مثلاً یک برچسب تولید شده توسط هوش مصنوعی یا شماره برنامه سفر) را نمایش دهید. این کار به کاربران شما تجربه کاوش نقشه آموزنده‌تری را بدون نیاز به مراجعه به کارت مکان دقیق ارائه می‌دهد.

آیکون‌ها و متن‌های موجود برای نشانگرهای مکان

شما می‌توانید یک آیکون نشانگر و متن نشانگر اختیاری را در هر PlaceMarker نمایش دهید.

آیکون‌های موجود عبارتند از:

  • Type : نوع مکان.
  • None : بدون آیکون.
نشانگرهای متن موجود عبارتند از:
  • Rating : امتیاز رتبه‌بندی.
  • PriceRange : محدوده قیمت (برای مثال، ۱۰ تا ۲۰ دلار).
  • OpenStatus : اینکه آیا یک کسب و کار باز است یا بسته.
  • Custom : متن سفارشی (برای مثال، "محبوب").

با استفاده از شناسه مکان ( PlaceId )، نام منبع ( ResourceName ) یا مختصات جغرافیایی ( Coordinates ) به مکان ارجاع دهید.

الزامات نمایش و انتساب

وقتی نشانگرهای نقشه Places UI Kit نمایش داده می‌شوند، نشانگرها نباید به صورت جداگانه ظاهر شوند. آنها باید تعاملی باشند و با کلیک یا لمس، یک کامپوننت یا لایت باکس جزئیات مکان مرتبط را باز کنند تا جریان‌های مورد نیاز برندسازی گوگل، انتساب مشارکت‌کننده و گزارش مشکل را ارائه دهند.

برای سناریوهایی که فضا محدود است ، به الزامات مربوط به عکس‌ها و نظرات ما مراجعه کنید.

نمونه‌های نشانگر مکان

ما توابع Jetpack Compose @Composable را ارائه می‌دهیم تا سربار پوشش View-to-Compose را از بین ببریم و از مشکلات عدم تطابق قالب جلوگیری کنیم.

سفارشی‌سازی‌های اولیه نشانگر

مثال کد زیر، سفارشی‌سازی‌های اولیه نشانگر مکان، از جمله پنهان کردن منقار حباب گفتار مثلثی برای نشانگر پیش‌فرض را نشان می‌دهد.

کاتلین

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")
    )
}

یک شنونده کلیک ایجاد کنید

شما می‌توانید یک تابع فراخوانی onClick برای اجرای اقدامات سفارشی هنگام لمس یک نشانگر مستقل ارائه دهید. با این حال، هنگامی که نشانگر روی یک نقشه (مثلاً درون یک MarkerComposable ) رندر می‌شود، رویدادهای لمس توسط نقشه متوقف می‌شوند. در این حالت، باید به جای نشانگر، از کنترل‌کننده onClick مربوط به MarkerComposable استفاده کنید.

مثال کد زیر نحوه استفاده از هندلر onClick مربوط به MarkerComposable را نشان می‌دهد.

کاتلین

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)
      }
    }
  }
}

مدیریت وضعیت بارگذاری و فراخوانی‌های مجدد

مثال کد زیر نحوه ارائه callbackها برای مدیریت خطاهای رندر یا داده‌های از دست رفته را نشان می‌دهد.

کاتلین

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)
        }
    )
}

استفاده از PlaceMarkerState برای قرار دادن نشانگرها روی نقشه

شیء Place به همراه موقعیت مکانی و نمای دید (viewport) برگردانده می‌شود تا به شما در تصمیم‌گیری برای محل قرار دادن نشانگر کمک کند.

کاتلین

// 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
    }
  }
}

مقیاس نشانگر را به اندازه دلخواه تنظیم کنید

کاتلین

// 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)
        }
      }
    }
  }
}