کامپوننت جزئیات مکان پیشرفته

نسخه پیشرفته کامپوننت Place Details همان ویژگی‌های Places Details Essentials را ارائه می‌دهد. همچنین به شما امکان می‌دهد دکمه‌های عملیاتی کامپوننت را پیکربندی کنید و گزینه‌های جستجو و فیلتر را برای نظرات و رسانه‌های نمایش داده شده اعمال کنید.

پشتیبانی داخلی از Jetpack Compose

کیت رابط کاربری Places توابع @Composable مربوط به Jetpack Compose را برای AdvancedPlaceDetailsCompact ارائه می‌دهد. این composableها از حالت hoisted، پشتیبانی از اصلاح‌کننده‌های داخلی و اسلات‌های DSL بومی Compose استفاده می‌کنند.

نمونه کد زیر نحوه استفاده از تابع composable را برای طرح‌بندی عمودی نشان می‌دهد.

کاتلین

import android.util.Log
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.dp
import com.google.android.libraries.places.api.model.Place
import com.google.android.libraries.places.compose.AdvancedPlaceDetailsCompact
import com.google.android.libraries.places.compose.PlaceReference
import com.google.android.libraries.places.compose.action.CornerAction
import com.google.android.libraries.places.compose.action.MainAction
import com.google.android.libraries.places.compose.Orientation

@Composable
fun SampleAdvancedPlaceDetailsCompactCard(
    placeId: String,
    bookmarkIcon: Painter,
    onSavePlaceClicked: (Place) -> Unit
) {
    AdvancedPlaceDetailsCompact(
        // defines the place to be displayed
        reference = PlaceReference.PlaceId(placeId),
        // defines the orientation
        orientation = Orientation.VERTICAL,
        // defines custom styling
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        preferTruncation = true,
        enableLightbox = true,
        mainActions = { place ->
            listOf(
                MainAction.OpenDirections(),
                MainAction.OpenWebsite(),
                MainAction.Call()
            )
        },
        // action button configuration
        cornerActions = { place ->
            listOf(
                CornerAction.Custom(
                    icon = bookmarkIcon,
                    text = "Save Place",
                    onClick = { onSavePlaceClicked(place) }
                )
            )
        },
        onPlaceLoaded = { place ->
            Log.d("Places", "Successfully loaded place: ${place.id}")
        },
        onPlaceLoadFailed = { exception ->
            Log.e("Places", "Failed to load place", exception)
        }
    ) {
        // --- Slot: Injected directly above the place name ---
        basicSectionTop {
            Text(
                text = "Featured in 'Top 10 Coffee Shops in SF'",
                style = MaterialTheme.typography.labelSmall,
                color = MaterialTheme.colorScheme.secondary,
                modifier = Modifier.padding(top = 4.dp, bottom = 2.dp)
            )
        }

        // --- Slot: Injected directly below the action buttons ---
        basicSectionBottom {
            Text(
                text = "Notes: Great quiet atmosphere for meetings.",
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant
            )
        }
    }
}

پیکربندی پیشرفته جزئیات مکان

برای دسترسی به ویژگی‌های پیشرفته، از AdvancedPlaceDetailsFragment یا AdvancedPlaceDetailsCompactFragment استفاده کنید.

پیکربندی دکمه‌های عملیاتی

برای تعریف و سفارشی‌سازی دکمه‌های عملیاتی، از رابط PlaceActionProvider مربوط به AdvancedPlaceDetailsFragment یا AdvancedPlaceDetailsCompactFragment استفاده کنید.

اگر از توابع @composable استفاده می‌کنید، از لامبداهای mainActions و cornerActions برای پیکربندی دکمه‌های عملیاتی استفاده کنید.

الزامات انتساب بصری

جزئیات را با دکمه‌های سفارشی، نمای فشرده قرار دهید
نمای فشرده جزئیات مکان پیشرفته با دکمه سفارشی

مهم: شما باید برای کاربران نهایی روشن کنید که چه زمانی یک دکمه اقدام سفارشی، اطلاعات کاربر را با شخص ثالثی غیر از گوگل به اشتراک می‌گذارد. به الزامات انتساب بصری مراجعه کنید.

مثال سمت راست یک تصویر سفارشی را نشان می‌دهد که به وضوح نشان می‌دهد اطلاعات کاربر به «Altostrat» ارسال خواهد شد.

اعمال گزینه‌های جستجو و فیلتر

از کلاس‌های SearchMediaOptions و SearchReviewsOptions از AdvancedPlaceDetailsFragment یا AdvancedPlaceDetailsCompactFragment برای فعال کردن جستجو و فیلتر کردن رسانه‌ها یا نظرات استفاده کنید.

اگر از توابع @composable استفاده می‌کنید، از com.google.android.libraries.places.compose.search.SearchMediaOptions برای فعال کردن جستجو و فیلتر کردن رسانه‌ها یا نظرات استفاده کنید.

ایجاد اسلات‌های محتوای سفارشی

گزینه‌های سفارشی برای قرار دادن اسلات محتوا

اسلات‌های محتوای سفارشی به شما امکان می‌دهند محتوای خود (مانند خلاصه‌های تولید شده توسط هوش مصنوعی، مهرهای زمانی برنامه سفر یا نشان‌های سفارشی) را مستقیماً به مناطق طرح‌بندی از پیش تعریف شده اضافه کنید.

الزامات انتساب و پیشنهادهای محتوا برای بخش‌های محتوایی

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

انجام دهید

برای جلوگیری از هرگونه ابهام در مورد منبع اطلاعات، سلسله مراتب بصری واضحی را بین جزئیات Google Place و محتوای سفارشی حفظ کنید.

جلوگیری از ابهام در مورد منبع اطلاعات

انجام دهید

بینش‌های محلی و ارزشمند متناسب با اهداف فوری کاربران خود را در نظر بگیرید. محتوای متناسب مانند پنجره‌های رزرو در لحظه یا موجودی فعلی به کاربران کمک می‌کند تا تصمیمات سریع‌تر و آگاهانه‌تری بگیرند.

ارائه بینش‌های ارزشمند

نکن

حتی اگر محتوای ارائه شده توسط گوگل را پنهان کرده‌اید، جزئیات موجود در گوگل پلیس، مانند رتبه‌بندی‌ها، نظرات یا ساعات کاری را کپی نکنید. انجام این کار می‌تواند کاربران را در مورد منبع محتوا و اینکه آیا از گوگل یا شخص ثالث است، گیج کند.

جزئیات موجود در Google Place را کپی نکنید

نکن

ادعاها یا نشان‌های بدون منبع (مثلاً «توصیه برتر!») را که ممکن است با تأییدیه‌های رسمی گوگل اشتباه گرفته شوند، نمایش ندهید. محتوای سفارشی باید صریحاً منبع خود را ذکر کند.

ادعاها یا نشان‌های نامشخص را نمایش ندهید

نکن

تبلیغات، متن بازاریابی، تخفیف‌های تبلیغاتی یا درخواست‌های اشتراک را در جعبه‌های سفارشی قرار ندهید.

تبلیغات، متن بازاریابی، تخفیف‌های تبلیغاتی یا درخواست‌های اشتراک را درج نکنید

برای افزودن محتوای سفارشی، از ترکیب‌بندی AdvancedPlaceDetailsCompact استفاده کنید. برای مشخص کردن موقعیت محتوا basicSectionTop یا basicSectionBottom استفاده کنید.

مثال‌های جزئیات مکان پیشرفته

سفارشی‌سازی دکمه‌های عملیاتی

از رابط PlaceActionProvider برای کنترل اینکه کدام اقدامات برای هر مکان در دسترس است، استفاده کنید.

کاتلین

class PlaceDetailsWidgetTestActivity : BaseActivity() {

// simplified example of starting the fragment
fun setupPPDFragment() {
   fullWidgetSelectedContent = AdvancedPlaceDetailsFragment.ALL_CONTENT.toMutableList()
   AdvancedPlaceDetailsFragment.newInstance(fullWidgetSelectedContent, Orientation.VERTICAL)
   supportFragmentManager
      .beginTransaction()
      .replace(R.id.fragment_container, fragment!!)
      .commitNow()
}

// you can set the callback elsewhere, but this is the ideal callback spot
override fun onAttachFragment(fragment: Fragment) {
    super.onAttachFragment(fragment)
    when (fragment) {
      is PlaceActionController -> setPlaceActionProvider(fragment)
    }
}

// have this callback return an empty list to hide all buttons
// if this callback isn't set, default buttons appear
 private fun setPlaceActionProvider(fragment: PlaceActionController) {
    fragment.setPlaceActionProvider(
        object : PlaceActionProvider {
        override fun getMainPlaceActions(place: Place): List<PlaceAction> = buildList {
            // predefined actions can be mixed in with custom ones
            add(PlaceAction.OPEN_IN_MAPS)

            // example of button with both text label and icon
            add(
              PlaceAction.builder()
                .setLabelTextResId(R.string.custom_action)
                .setIconResId(R.drawable.gs_custom_action_icon)
                .setContentDescriptionResId(R.string.custom_action_description)
                .setOnClickListener { /* todo perform action */ }
                .build()
            )

            // icon only button
            add(
              PlaceAction.builder()
                .setIconResId(R.drawable.custom_action_icon_2)
                .setContentDescriptionResId(R.string.custom_action_description_2)
                .setOnClickListener { /* todo perform action */}
                .build()
            )

            // text label only button
            add(
              PlaceAction.builder()
                .setLabelTextResId(R.string.custom_action_3)
                .setContentDescriptionResId(R.string.custom_action_description_2)
                .setOnClickListener {/* todo perform action */ }
                .build()
            )
          }

         /**
         You can also specify whether corner buttons should appear.  
         For either callback, returning an empty list results in no buttons appearing
         */
         override fun getCornerPlaceActions(place: Place): List<PlaceAction> {
           return emptyList()
         }

        override fun addPlaceActionsChangedListener(
          listener: PlaceActionProvider.OnChangedListener
        ) {
          // in this example, just one listener and widget
          this@HostAppActivity.listener = listener
        }

        override fun removePlaceActionsChangedListener(
          listener: PlaceActionProvider.OnChangedListener
        ) {
          // if there are multiple listeners, remove only the provided listener
          this@HostAppActivity.listener = null
        }
      })
  }
}

افزودن اقدامات سفارشی و از پیش تعریف شده

این نمونه یک دکمه‌ی تغییر وضعیت برای کاربر اضافه می‌کند تا بتواند یک مکان را به لیست علاقه‌مندی‌ها اضافه کند یا از لیست علاقه‌مندی‌ها حذف کند.

کاتلین

private var listener: PlaceActionProvider.OnChangedListener? = null

private fun setPlaceActionProvider(fragment: PlaceActionController) {
    fragment.setPlaceActionProvider(
      object : PlaceActionProvider {
        private var placeFavorited = false

        override fun getMainPlaceActions(place: Place): List<PlaceAction> {
          val buttonList = mutableListOf<PlaceAction>()

          if (placeFavorited) {
            buttonList.add(
              PlaceAction.builder()
                .setLabelTextResId(R.string.place_details_button_config_favorite)
                .setIconResId(R.drawable.gs_web_vd_theme_24)
                .setOnClickListener {
                  placeFavorited = !placeFavorited
                  refreshButtonConfigs()
                }
                .build()
            )
          } else {
            buttonList.add(
              PlaceAction.builder()
                .setLabelTextResId(R.string.place_details_button_config_unfavorite)
                .setIconResId(R.drawable.gs_web_vd_theme_24)
                .setOnClickListener {
                  placeFavorited = !placeFavorited
                  refreshButtonConfigs()
                }
                .build()
            )
          }

          return buttonList
        }

        override fun addPlaceActionsChangedListener(
          listener: PlaceActionProvider.OnChangedListener
        ) {
          this@PlaceDetailsWidgetTestActivity.listener = listener
        }

        override fun removePlaceActionsChangedListener(
          listener: PlaceActionProvider.OnChangedListener
        ) {
          // if there are multiple listeners, remove only the provided listener
          this@PlaceDetailsWidgetTestActivity.listener = null
        }
      }
    )
  }

private fun refreshButtonConfigs() {
    listener?.onPlaceActionsChanged()
}

استفاده از دکمه‌های استاندارد از پیش تعریف شده

دکمه‌های عملیاتی ایجاد کنید که اقدامات استاندارد تعریف‌شده توسط گوگل را انجام دهند.

کاتلین

  override fun getMainPlaceActions(place: Place): List<PlaceAction> {
    val buttonList = mutableListOf<PlaceAction>()
// these buttons will have different background and text color than user-created buttons.  
    // Text and icon button
    buttonList.add(PlaceAction.OPEN_IN_MAPS)
    // Icon-only buttons not enabled for main action buttons
    // Use of kotlin extension to do the same.  see
    PlaceAction.OPEN_IN_MAPS {
       setIconResId(0)
     }

    return buttonList
  }

فیلتر کردن نظرات و رسانه‌ها

این نمونه کد فقط رسانه‌ها و نظراتی را نشان می‌دهد که به «اسپاگتی» و «خوشمزه» اشاره کرده‌اند.

کاتلین

    import com.google.android.libraries.places.widget.AdvancedPlaceDetailsFragment
    import com.google.android.libraries.places.widget.model.SearchMediaOptions
    import com.google.android.libraries.places.widget.model.SearchReviewsOptions
    import com.google.android.libraries.places.widget.model.Orientation
    import com.google.android.libraries.places.R
  
     // 1. Create options using the Java builders (called from Kotlin)
    val mediaOptions = SearchMediaOptions.builder()
        .setQuery("spaghetti")
        .setRankPreference(SearchMediaOptions.RankPreference.MOST_RELEVANT)
        .build()

    val reviewOptions = SearchReviewsOptions.builder()
        .setQuery("tasty")
        .setRankPreference(SearchReviewsOptions.RankPreference.NEWEST)
        .build()

    // 2. Create the fragment
    val fragment = AdvancedPlaceDetailsFragment.newInstance(
        AdvancedPlaceDetailsFragment.STANDARD_CONTENT,
        Orientation.VERTICAL,
        R.style.PlacesMaterialTheme
    )

    // 3. Apply options to the fragment
    fragment.applySearchMediaOptions(mediaOptions)
    fragment.applySearchReviewsOptions(reviewOptions)

ایجاد اسلات‌های محتوا

کاتلین

import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import com.google.android.libraries.places.compose.AdvancedPlaceDetailsCompact
import com.google.android.libraries.places.compose.PlaceReference

@Composable
fun ItineraryPlaceCard(placeId: String) {
    AdvancedPlaceDetailsCompact(
        reference = PlaceReference.PlaceId(placeId)
    ) {
        // Slot: Injected directly above the place name
        basicSectionTop {
            Text(
                text = "Day 2 • 2:30 PM",
                style = MaterialTheme.typography.labelSmall,
                color = MaterialTheme.colorScheme.primary
            )
        }
        
        // Slot: Injected directly below the main action buttons
        basicSectionBottom {
            NotesCard(
                notes = "Great quiet atmosphere for morning meetings. Famous for house-roasted pour-overs."
            )
        }
    }
}