Componente Place Details avançado
A versão Advanced do componente Place Details oferece os mesmos recursos do Place Details Essentials. Ele também permite configurar os botões de ação do componente e aplicar opções de pesquisa e filtragem às avaliações e mídias mostradas.
Suporte integrado ao Jetpack Compose
O Kit de Interface do Places oferece funções do Jetpack Compose @Composable para AdvancedPlaceDetailsCompact. Esses elementos combináveis usam estado elevado, suporte a modificadores integrados e DSLs de slot nativas do Compose.
O exemplo de código abaixo demonstra como usar a função combinável para um layout vertical.
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 ) } } }
Configuração avançada do Place Details
Use o AdvancedPlaceDetailsFragment ou o AdvancedPlaceDetailsCompactFragment para acessar recursos avançados.
Configurar botões de ação
Use a interface PlaceActionProvider de AdvancedPlaceDetailsFragment ou AdvancedPlaceDetailsCompactFragment para definir e personalizar botões de ação.
Se você estiver usando funções @composable, use lambdas mainActions e cornerActions para configurar botões de ação.
Requisitos de atribuição visual
Importante: você precisa deixar claro para os usuários finais quando um botão de ação personalizada compartilhar informações do usuário com terceiros que não sejam o Google. Consulte os requisitos de atribuição visual.
O exemplo à direita mostra uma imagem personalizada que deixa claro que as informações do usuário serão enviadas para "Altostrat".
Aplicar opções de pesquisa e filtragem
Use as classes SearchMediaOptions e SearchReviewsOptions de AdvancedPlaceDetailsFragment ou AdvancedPlaceDetailsCompactFragment para ativar a pesquisa e a filtragem de mídia ou avaliações.
Se você estiver usando funções do @composable, use com.google.android.libraries.places.compose.search.SearchMediaOptions para ativar a pesquisa e a filtragem de mídia ou avaliações.
Criar espaços de conteúdo personalizados
Com os espaços de conteúdo personalizado, você pode adicionar seu próprio conteúdo (como resumos gerados por IA, marcações de tempo de itinerário ou selos personalizados) diretamente em zonas de layout predefinidas.
Requisitos de atribuição e sugestões de conteúdo para espaços de conteúdo
Quando um espaço de conteúdo personalizado é montado, a declaração é atualizada automaticamente para esclarecer qual conteúdo é fornecido pelo Google e que parte dele é fornecida por terceiros.
O que fazer
Mantenha uma hierarquia visual clara entre os detalhes do Google Place e o conteúdo personalizado para evitar qualquer ambiguidade sobre a origem das informações.
O que fazer
Considere insights localizados e de alto valor, adaptados às metas imediatas dos usuários. Conteúdo personalizado, como janelas de reserva em tempo real ou disponibilidade atual, ajuda os usuários a tomar decisões mais rápidas e informadas.
O que não fazer
Não duplique os Place Details do Google, como classificações, avaliações ou horário de funcionamento, mesmo que você tenha ocultado o conteúdo fornecido pelo Google. Isso pode confundir os usuários sobre a origem do conteúdo e se ele vem do Google ou de terceiros.
O que não fazer
Não mostre declarações ou selos sem atribuição (por exemplo, "Melhor recomendação!") que possam ser confundidos com endossos oficiais do Google. O conteúdo personalizado precisa atribuir explicitamente a fonte.
O que não fazer
Não inclua anúncios, textos de marketing, descontos promocionais ou solicitações de assinatura em contêineres de lugares personalizados.
Para adicionar conteúdo personalizado, use o elemento combinável AdvancedPlaceDetailsCompact. Use basicSectionTop ou basicSectionBottom para especificar a posição do conteúdo.
Exemplos avançados de Place Details
Personalizar botões de ação
Use a interface PlaceActionProvider para controlar quais ações estão disponíveis para cada lugar.
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 } }) } }
Adicionar ações personalizadas e predefinidas
Este exemplo adiciona um botão ativar/desativar para que o usuário marque ou desmarque um lugar como favorito.
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() }
Usar botões padrão predefinidos
Crie botões de ação que realizam ações padrão definidas pelo 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 }
Filtrar avaliações e mídia
Este exemplo de código mostra apenas mídias e avaliações que mencionam "espaguete" e "gostoso".
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)
Criar slots de conteúdo
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." ) } } }