Componente Advanced Place Details

La versione avanzata del componente Place Details offre le stesse funzionalità di Places Details Essentials. Consente inoltre di configurare i pulsanti di azione del componente e di applicare opzioni di ricerca e filtro alle recensioni e ai contenuti multimediali visualizzati.

Supporto integrato di Jetpack Compose

Places UI Kit fornisce funzioni @Composable Jetpack Compose per AdvancedPlaceDetailsCompact. Questi composable utilizzano lo stato sollevato, il supporto dei modificatori integrati e i DSL di slot nativi di Compose.

Il seguente esempio di codice mostra come utilizzare la funzione componibile per un layout verticale.

Kotlin

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

Configurazione avanzata di Place Details

Utilizza AdvancedPlaceDetailsFragment o AdvancedPlaceDetailsCompactFragment per accedere alle funzionalità avanzate.

Configurare i pulsanti di azione

Utilizza l'interfaccia PlaceActionProvider di AdvancedPlaceDetailsFragment o AdvancedPlaceDetailsCompactFragment per definire e personalizzare i pulsanti di azione.

Se utilizzi le funzioni @composable, utilizza le espressioni lambda mainActions e cornerActions per configurare i pulsanti di azione.

Requisiti di attribuzione visiva

Visualizzazione compatta dei dettagli del luogo con pulsanti personalizzati
Visualizzazione compatta dei dettagli avanzati del luogo con pulsante personalizzato

Importante:devi comunicare chiaramente agli utenti finali quando un pulsante di azione personalizzata condividerà le informazioni dell'utente con una terza parte diversa da Google. Consulta i requisiti di attribuzione visiva.

L'esempio a destra mostra un'immagine personalizzata che indica chiaramente che le informazioni dell'utente verranno inviate ad "Altostrat".

Applicare le opzioni di ricerca e filtro

Utilizza le classi SearchMediaOptions e SearchReviewsOptions di AdvancedPlaceDetailsFragment o AdvancedPlaceDetailsCompactFragment per attivare la ricerca e il filtro per contenuti multimediali o recensioni.

Se utilizzi le funzioni @composable, utilizza com.google.android.libraries.places.compose.search.SearchMediaOptions per attivare la ricerca e il filtro per contenuti multimediali o recensioni.

Creare slot di contenuti personalizzati

Opzioni di posizionamento degli slot di contenuti personalizzati

Gli spazi per i contenuti personalizzati ti consentono di aggiungere i tuoi contenuti (ad esempio riepiloghi generati dall'AI, timestamp dell'itinerario o badge personalizzati) direttamente nelle zone di layout predefinite.

Requisiti di attribuzione e suggerimenti per i contenuti degli spazi pubblicitari

Quando viene montato uno spazio per i contenuti personalizzati, l'informativa si aggiorna automaticamente per chiarire quali contenuti sono forniti da Google e quali da terze parti.

Cosa fare

Mantieni una gerarchia visiva chiara tra i dettagli di Google Place e i contenuti personalizzati per evitare ambiguità sull'origine delle informazioni.

Evitare ambiguità sull'origine delle informazioni

Cosa fare

Prendi in considerazione approfondimenti localizzati e di alto valore personalizzati in base agli obiettivi immediati degli utenti. Contenuti personalizzati come finestre di prenotazione in tempo reale o disponibilità attuale aiutano gli utenti a prendere decisioni più rapide e informate.

Fornire approfondimenti di alto valore

Cosa non fare

Non duplicare i dettagli esistenti di Google Places, come valutazioni, recensioni o orari di apertura, anche se hai nascosto i contenuti forniti da Google. In questo modo, gli utenti potrebbero non capire la fonte dei contenuti e se provengono da Google o da una terza parte.

Non duplicare i dettagli di Google Places esistenti

Cosa non fare

Non mostrare affermazioni o badge non attribuiti (ad esempio "Consiglio migliore") che potrebbero essere scambiati per approvazioni ufficiali di Google. I contenuti personalizzati devono attribuire esplicitamente la fonte.

Non mostrare badge o affermazioni non attribuite

Cosa non fare

Non includere annunci, testi di marketing, sconti promozionali o inviti all'abbonamento all'interno dei contenitori di luoghi personalizzati.

Non includere annunci, testi di marketing, sconti promozionali o inviti all'abbonamento

Per aggiungere contenuti personalizzati, utilizza il componibile AdvancedPlaceDetailsCompact. Utilizza basicSectionTop o basicSectionBottom per specificare la posizione del contenuto.

Esempi di Place Details avanzati

Personalizzare i pulsanti di azione

Utilizza l'interfaccia PlaceActionProvider per controllare quali azioni sono disponibili per ogni luogo.

Kotlin

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

Aggiungere azioni personalizzate e predefinite

Questo esempio aggiunge un pulsante di attivazione/disattivazione per consentire a un utente di aggiungere un luogo ai preferiti o rimuoverlo.

Kotlin

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

Utilizzare i pulsanti standard predefiniti

Crea pulsanti di azione che eseguono azioni standard definite da Google.

Kotlin

  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
  }

Filtrare recensioni e contenuti multimediali

Questo esempio di codice mostra solo i contenuti multimediali e le recensioni che menzionano "spaghetti" e "buoni".

Kotlin

    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)

Creare spazi per i contenuti

Kotlin

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