Sélectionnez une plate-forme : Android iOS JavaScript

Composant Place Details

Le composant Place Details du kit d'UI Places vous permet d'ajouter un composant d'UI individuel qui affiche les détails d'un lieu dans votre application. Ce composant est personnalisable.

Composant compact "Détails sur le lieu"

Le composant "Détails du lieu" peut être utilisé de manière indépendante ou en association avec d'autres API et services Google Maps Platform. Le composant accepte un ID de lieu, un nom de ressource ou des coordonnées de latitude/longitude, et renvoie les informations Place Details (Détails du lieu) affichées.

Le composant Place Details est entièrement personnalisable. Vous pouvez modifier les polices, les couleurs et les rayons des angles pour qu'ils correspondent à votre cas d'utilisation et aux consignes relatives à votre identité visuelle. Vous pouvez personnaliser l'apparence des détails du lieu en créant un thème qui étend PlacesMaterialTheme et fournit des remplacements pour les attributs du thème. Vous pouvez également personnaliser les champs d'informations sur les lieux à inclure en spécifiant une liste d'entrées de contenu, chacune correspondant à une information affichée sur le lieu.

Variantes de mise en page

Le composant Détails du lieu est compatible avec deux variantes de mise en page principales :

  • Compact : mise en page permettant de prévisualiser les informations clés.
  • Complet : une mise en page complète affichant tous les détails disponibles sur le lieu.

La mise en page compacte peut être affichée en orientation verticale ou horizontale. Cela vous permet d'intégrer le composant dans différentes mises en page et tailles d'écran. La mise en page complète ne peut être affichée qu'à la verticale.

mises en page horizontales et verticales ;
Mises en page horizontales et verticales

Le composant "Détails du lieu" vous permet de contrôler précisément le contenu affiché dans le composant. Chaque élément (comme les photos, les avis et les coordonnées) peut être affiché ou masqué individuellement, ce qui permet de personnaliser précisément l'apparence des composants et la densité des informations.

Options de contenu des détails sur le lieu
Options d'affichage du contenu

Vue compacte des détails sur le lieu

Le fragment compact Place Details (PlaceDetailsCompactFragment) affiche les détails d'un lieu sélectionné en utilisant un minimum d'espace. Cela peut être utile dans une fenêtre d'informations mettant en évidence un lieu sur une carte, dans une expérience de réseau social comme le partage d'une position dans une discussion, comme suggestion pour sélectionner votre position actuelle ou dans un article de presse pour faire référence au lieu sur Google Maps.

Vue complète des détails sur le lieu

La vue complète des détails sur le lieu (PlaceDetailsFragment) offre une plus grande surface pour afficher les informations sur le lieu et vous permet d'afficher plus de types d'informations.

Options d'affichage du contenu

Vous pouvez spécifier le contenu à afficher à l'aide des énumérations dans PlaceDetailsCompactFragment.Content ou PlaceDetailsFragment.Content.

Affichage compact Affichage du livre entier
  • Photo du lieu
  • Adresse du lieu
  • Note et nombre de notes
  • Type de lieu
  • Prix
  • Informations sur l'entrée accessible
  • État "Ouvert"
  • Montage photo du lieu
  • Adresse du lieu
  • Note et nombre de notes
  • Type de lieu
  • Prix
  • Informations sur l'accessibilité
  • État "Ouvert"
  • Horaires d'ouverture
  • Résumé éditorial
  • Site Web
  • Numéro de téléphone
  • Avis affichés dans un onglet dédié
  • Plus code
  • Liste des fonctionnalités, affichée dans un onglet dédié
  • Informations spécifiques à un type de lieu, comme les prix des carburants pour les stations-service

Facturation

Lorsque vous utilisez le kit UI Place Details, vous êtes facturé chaque fois que la méthode .loadWithPlaceId(), .loadWithResourceName() ou loadWithCoordinates() est appelée. Si vous chargez le même lieu plusieurs fois, chaque requête vous sera facturée.

Pour éviter d'être facturé plusieurs fois, n'ajoutez pas directement .loadWithPlaceId() ni .loadWithResourceName() dans les méthodes de cycle de vie Android. Par exemple, n'appelez pas directement .loadWithPlaceId() ni .loadWithResourceName() dans la méthode onResume().

Ajouter des détails sur les lieux à votre application

Vous pouvez ajouter des détails sur un lieu à votre application en ajoutant un fragment à une mise en page. Lorsque vous instanciez le fragment, vous pouvez personnaliser l'apparence des informations sur le lieu en fonction de vos besoins et de l'apparence de votre application. En savoir plus sur la personnalisation

Trois méthodes sont disponibles en Kotlin et en Java : une pour charger le fragment avec un ID de lieu (loadWithPlaceId()), une pour charger le fragment avec un nom de ressource (loadWithResourceName()) et une pour charger le fragment avec des coordonnées de latitude/longitude (loadWithCoordinates()). Vous pouvez choisir une ou plusieurs méthodes.

La position par défaut de la vue compacte est verticale. Si vous souhaitez une mise en page horizontale, spécifiez Orientation.HORIZONTAL. Vous pouvez également spécifier Orientation.VERTICAL pour plus de clarté. La vue complète ne peut être affichée qu'à la verticale.

Consultez les exemples dans la section Exemples de composant Détails du lieu.

Personnaliser l'apparence visuelle

Personnalisation visuelle des détails sur le lieu
Exemples de personnalisation visuelle

Le kit d'UI Places offre une approche de système de conception pour la personnalisation visuelle, basée en gros sur Material Design (avec quelques modifications spécifiques à Google Maps). Consultez la documentation de référence de Material Design pour Couleur et Typographie. Par défaut, le style respecte le langage de conception visuelle de Google Maps.

Options de personnalisation des détails du lieu

Lorsque vous instanciez un fragment, vous pouvez spécifier un thème qui remplace l'un des attributs de style par défaut. Tous les attributs de thème qui ne sont pas remplacés utilisent les styles par défaut. Si vous souhaitez prendre en charge un thème sombre, vous pouvez ajouter une entrée pour la couleur dans values-night/colors.xml.

  <style name="CustomizedPlaceDetailsTheme" parent="PlacesMaterialTheme">
    <item name="placesColorPrimary">@color/app_primary_color</item>
    <item name="placesColorOnSurface">@color/app_color_on_surface</item>
    <item name="placesColorOnSurfaceVariant">@color/app_color_on_surface</item>
  
    <item name="placesTextAppearanceBodySmall">@style/app_text_appearence_small</item>
  
    <item name="placesCornerRadius">20dp</item>
  </style>

Vous pouvez personnaliser les styles suivants :

Personnalisation de la couleur et de la typographie des boîtes de dialogue
Personnalisation de la couleur et de la typographie de la boîte de dialogue
Attribut de thème Utilisation
Couleur
placesColorSurface Arrière-plan du conteneur et de la boîte de dialogue
placesColorOutlineDecorative Bordure du conteneur
placesColorPrimary Liens, indicateur de chargement, icônes de présentation
placesColorOnSurface Titres, contenu de la boîte de dialogue
placesColorOnSurfaceVariant Informations sur le lieu
placesColorSecondaryContainer Arrière-plan du bouton
placesColorOnSecondaryContainer Texte et icône du bouton
placesColorNeutralContainer Formes de l'espace réservé de chargement et badge de date d'avis
placesColorOnNeutralContainer Date de l'avis, erreur de chargement
placesColorPositiveContainer Badge "Borne de recharge pour VE disponible"
placesColorOnPositiveContainer Contenu du badge de borne de recharge pour VE disponible
placesColorPositive Libellé "Ouvert" pour les lieux
placesColorNegative Libellé "Fermé" pour les lieux
placesColorInfo Icône Entrée accessible
placesColorButtonBorder Boutons "Ouvrir dans Maps" et "OK"
   
Typographie
placesTextAppearanceBodySmall Informations sur le lieu
placesTextAppearanceBodyMedium Informations sur le lieu, contenu de la boîte de dialogue
placesTextAppearanceLabelMedium Contenu des badges
placesTextAppearanceLabelLarge Contenu du bouton
placesTextAppearanceHeadlineMedium Titres de boîte de dialogue
placesTextAppearanceDisplaySmall Nom de lieu
placesTextAppearanceTitleSmall Nom de lieu
   
Espacement
placesSpacingExtraSmall
placesSpacingSmall
placesSpacingMedium
placesSpacingLarge
placesSpacingExtraLarge
placesSpacingTwoExtraLarge
   
Mesures
placesBorderWidth Conteneur
placesBorderWidthButton
   
Forme
placesCornerRadius Conteneur
placesCornerRadiusButton Boutons "Ouvrir dans Maps" et "OK" (à l'exclusion du bouton en forme d'icône ronde)
placesCornerRadiusThumbnail Placer une vignette
placesCornerRadiusCollageOuter Montage multimédia
placesCornerRadiusCard Fiche d'établissement, fiche d'avis d'utilisateur
placesCornerRadiusDialog Boîte de dialogue d'informations Google Maps
   
Attribution de la marque Google Maps
placesColorAttributionLightTheme Bouton d'attribution et de divulgation Google Maps avec thème clair (énumérations pour le blanc, le gris et le noir)
placesColorAttributionDarkTheme Bouton d'attribution et de divulgation du thème sombre Google Maps (énumérations pour le blanc, le gris et le noir)

Consultez les exemples dans la section Exemples de composant Détails du lieu.

Personnalisation de la largeur et de la hauteur

Vues compactes

Largeurs recommandées :

  • Orientation verticale : entre 180 et 300 dp.
  • Orientation horizontale : entre 180 dp et 500 dp.

Les largeurs inférieures à 160 dp peuvent ne pas s'afficher correctement.

Il est recommandé de ne pas définir de hauteur pour les vues compactes. Cela permettra au contenu de la fenêtre de définir la hauteur, ce qui permettra d'afficher toutes les informations.

Vues complètes

Pour les vues complètes, la largeur recommandée est comprise entre 250 dp et 450 dp. Une largeur inférieure à 250 dp peut ne pas s'afficher correctement.

Vous pouvez définir la hauteur du composant : la vue verticale des détails du lieu défilera verticalement dans l'espace alloué.

Il est recommandé de définir une hauteur pour les vues complètes. Cela permettra au contenu de la fenêtre de défiler correctement.

Couleurs d'attribution

attribution
Attribution

Les Conditions d'utilisation de Google Maps vous obligent à utiliser l'une des trois couleurs de la marque pour l'attribution Google Maps. Cette attribution doit être visible et accessible lorsque des modifications de personnalisation ont été apportées.

Vous pouvez choisir parmi trois couleurs de marque, qui peuvent être définies indépendamment pour les thèmes clair et sombre :

  • Thème clair : placesColorAttributionLight avec des valeurs d'énumération pour le blanc, le gris et le noir.
  • Thème sombre : placesColorAttributionDark avec des valeurs d'énumération pour le blanc, le gris et le noir.

Exemples de composants Place Details

Créer une vue compacte ou complète

Kotlin

              
        // We create a new instance of the fragment using its factory method.
        // We can specify which content to show, the orientation, and a custom theme.
        val fragment = PlaceDetailsCompactFragment.newInstance(
            PlaceDetailsCompactFragment.ALL_CONTENT, // Show all available content.
            orientation,
            R.style.CustomizedPlaceDetailsTheme,
        ).apply {
            // The PlaceLoadListener provides callbacks for when the place data is successfully
            // loaded or when an error occurs. This is where we update our UI state.
            setPlaceLoadListener(object : PlaceLoadListener {
                override fun onSuccess(place: Place) {
                    Log.d(TAG, &quot;Place loaded: ${place.id}&quot;)
                    // Once the data is loaded, we hide the loading indicator and show the fragment.
                    binding.loadingIndicatorMain.visibility = View.GONE
                    binding.placeDetailsContainer.visibility = View.VISIBLE
                    binding.dismissButton.visibility = View.VISIBLE
                }

                override fun onFailure(e: Exception) {
                    Log.e(TAG, &quot;Place failed to load&quot;, e)
                    // On failure, we hide the UI and notify the user.
                    dismissPlaceDetails()
                    Toast.makeText(this@MainActivity, &quot;Failed to load place details.&quot;, Toast.LENGTH_SHORT).show()
                }
            })
        }

        // We add the fragment to our layout&#39;s container view.
        // `commitNow()` is used to ensure the fragment is immediately added and available,
        // which is important because we need to call a method on it right after.
        supportFragmentManager
            .beginTransaction()
            .replace(binding.placeDetailsContainer.id, fragment)
            .commitNow()

        // **This is the key step**: After adding the fragment, we call `loadWithPlaceId`
        // to trigger the data loading process for the selected place.
        // We use `post` to ensure this runs after the layout has been measured,
        // which can prevent potential timing issues.
        binding.root.post {
            fragment.loadWithPlaceId(placeId)
        }
    }

Java

      
PlaceDetailsCompactFragment fragment =
  PlaceDetailsCompactFragment.newInstance(
        Orientation.HORIZONTAL,
        Arrays.asList(Content.ADDRESS, Content.TYPE, Content.RATING, Content.ACCESSIBLE_ENTRANCE_ICON),
        R.style.CustomizedPlaceDetailsTheme);
    
fragment.setPlaceLoadListener(
  new PlaceLoadListener() {
        @Override public void onSuccess(Place place) { ... }
    
        @Override public void onFailure(Exception e) { ... }
});
    
getSupportFragmentManager()
      .beginTransaction()
      .add(R.id.fragment_container, fragment)
      .commitNow();
    
// Load the fragment with a Place ID.
fragment.loadWithPlaceId(placeId);
      
// Load the fragment with a resource name.
fragment.loadWithResourceName(resourceName);

Cet exemple de code complet détermine l'orientation de la vue compacte de manière programmatique en fonction de la configuration de l'appareil de l'utilisateur.

Kotlin

        
package com.example.placedetailsuikit

import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.location.Location
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.lifecycle.ViewModel
import com.example.placedetailsuikit.databinding.ActivityMainBinding
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.PointOfInterest
import com.google.android.libraries.places.api.Places
import com.google.android.libraries.places.api.model.Place
import com.google.android.libraries.places.widget.PlaceDetailsCompactFragment
import com.google.android.libraries.places.widget.PlaceLoadListener
import com.google.android.libraries.places.widget.model.Orientation

private const val TAG = &quot;PlacesUiKit&quot;

/**
 * A simple ViewModel to store UI state that needs to survive configuration changes.
 * In this case, it holds the ID of the selected place. Using a ViewModel is good practice
 * as it prevents data loss during events like screen rotation, ensuring a
 * seamless user experience.
 */
class MainViewModel : ViewModel() {
    var selectedPlaceId: String? = null
}

/**
 * This activity serves as a basic example of integrating the Place Details UI Kit.
 * It demonstrates the fundamental steps required:
 * 1. Setting up a Google Map.
 * 2. Requesting location permissions to center the map.
 * 3. Handling clicks on Points of Interest (POIs) to get a Place ID.
 * 4. Using the Place ID to load and display place details in a [PlaceDetailsCompactFragment].
 */
class MainActivity : AppCompatActivity(), OnMapReadyCallback, GoogleMap.OnPoiClickListener {
    // ViewBinding provides type-safe access to views defined in the XML layout,
    // eliminating the need for `findViewById` and preventing null pointer exceptions.
    private lateinit var binding: ActivityMainBinding
    private var googleMap: GoogleMap? = null

    // The FusedLocationProviderClient is the main entry point for interacting with the
    // fused location provider, which intelligently manages the underlying location technologies.
    private lateinit var fusedLocationClient: FusedLocationProviderClient

    // Using registerForActivityResult is the modern, recommended approach for handling
    // permission requests. It decouples the request from the handling logic, making the
    // code cleaner and easier to manage compared to the older `onRequestPermissionsResult` callback.
    private lateinit var requestPermissionLauncher: ActivityResultLauncher&lt;Array&lt;String&gt;&gt;

    // The `by viewModels()` delegate provides a lazy-initialized ViewModel scoped to this Activity.
    // This ensures that we get the same ViewModel instance across configuration changes.
    private val viewModel: MainViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // The ActivityResultLauncher is initialized here. The lambda defines the callback
        // that will be executed once the user responds to the permission dialog.
        requestPermissionLauncher =
            registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -&gt;
                // We check if either fine or coarse location permission was granted.
                if (permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true || permissions[Manifest.permission.ACCESS_COARSE_LOCATION] == true) {
                    Log.d(TAG, &quot;Location permission granted by user.&quot;)
                    fetchLastLocation()
                } else {
                    // If permission is denied, we inform the user and default to a known location.
                    // This ensures the app remains functional even without location access.
                    Log.d(TAG, &quot;Location permission denied by user.&quot;)
                    Toast.makeText(
                        this,
                        &quot;Location permission denied. Showing default location.&quot;,
                        Toast.LENGTH_LONG
                    ).show()
                    moveToSydney()
                }
            }

        // enableEdgeToEdge() allows the app to draw behind the system bars for a more immersive experience.
        enableEdgeToEdge()
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.dismissButton.setOnClickListener {
            dismissPlaceDetails()
        }

        // --- Crucial: Initialize Places SDK ---
        // It&#39;s essential to initialize the Places SDK before making any other Places API calls.
        // This should ideally be done once, for example, in the Application&#39;s `onCreate`.
        val apiKey = BuildConfig.PLACES_API_KEY
        if (apiKey.isEmpty() || apiKey == &quot;YOUR_API_KEY&quot;) {
            // A valid API key is required for the Places SDK to function.
            Log.e(TAG, &quot;No api key&quot;)
            Toast.makeText(
                this,
                &quot;Add your own API_KEY in local.properties&quot;,
                Toast.LENGTH_LONG
            ).show()
            finish()
            return
        }

        // `initializeWithNewPlacesApiEnabled` is used to opt-in to the new SDK version.
        Places.initializeWithNewPlacesApiEnabled(applicationContext, apiKey)

        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        // ------------------------------------

        // The SupportMapFragment is the container for the map. `getMapAsync` allows us to
        // work with the GoogleMap object via a callback once it&#39;s fully initialized.
        val mapFragment =
            supportFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment?
        mapFragment?.getMapAsync(this)

        // This block handles restoration after a configuration change (e.g., screen rotation).
        // If a place was selected before the rotation, its ID is stored in the ViewModel.
        // We use this ID to immediately show the details fragment again.
        if (viewModel.selectedPlaceId != null) {
            viewModel.selectedPlaceId?.let { placeId -&gt;
                Log.d(TAG, &quot;Restoring PlaceDetailsFragment for place ID: $placeId&quot;)
                showPlaceDetailsFragment(placeId)
            }
        }
    }

    /**
     * This callback is triggered when the GoogleMap object is ready to be used.
     * All map setup logic should be placed here.
     */
    override fun onMapReady(map: GoogleMap) {
        Log.d(TAG, &quot;Map is ready&quot;)
        googleMap = map
        // Setting the OnPoiClickListener allows us to capture user taps on points of interest.
        googleMap?.setOnPoiClickListener(this)

        // After the map is ready, we determine the initial camera position based on location permissions.
        if (isLocationPermissionGranted()) {
            fetchLastLocation()
        } else {
            requestLocationPermissions()
        }
    }

    /**
     * A helper function to centralize the check for location permissions.
     */
    private fun isLocationPermissionGranted(): Boolean {
        return ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) == PackageManager.PERMISSION_GRANTED ||
                ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.ACCESS_COARSE_LOCATION
                ) == PackageManager.PERMISSION_GRANTED
    }

    /**
     * This function triggers the permission request flow. The result is handled by the
     * ActivityResultLauncher defined in `onCreate`.
     */
    private fun requestLocationPermissions() {
        Log.d(TAG, &quot;Requesting location permissions.&quot;)
        requestPermissionLauncher.launch(
            arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION
            )
        )
    }

    /**
     * Fetches the device&#39;s last known location. This is a fast and battery-efficient way
     * to get a location fix. It should only be called after verifying permissions.
     */
    @SuppressLint(&quot;MissingPermission&quot;)
    private fun fetchLastLocation() {
        // Double-checking permissions here is a good practice, although the call sites are already guarded.
        if (isLocationPermissionGranted()) {
            fusedLocationClient.lastLocation
                .addOnSuccessListener { location: Location? -&gt;
                    if (location != null) {
                        val userLocation = LatLng(location.latitude, location.longitude)
                        googleMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 13f))
                        Log.d(TAG, &quot;Moved to user&#39;s last known location.&quot;)
                    } else {
                        // `lastLocation` can be null if the location has never been recorded.
                        // In this case, we fall back to a default location.
                        Log.d(TAG, &quot;Last known location is null. Falling back to Sydney.&quot;)
                        moveToSydney()
                    }
                }
                .addOnFailureListener {
                    // This listener handles errors in the location fetching process.
                    Log.e(TAG, &quot;Failed to get location.&quot;, it)
                    moveToSydney()
                }
        }
    }

    /**
     * Moves the map camera to a default, hardcoded location (Sydney).
     * This serves as a reliable fallback.
     */
    private fun moveToSydney() {
        val sydney = LatLng(-33.8688, 151.2093)
        googleMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 13f))
        Log.d(TAG, &quot;Moved to Sydney&quot;)
    }

    /**
     * This is the callback for the `OnPoiClickListener`. It&#39;s triggered when a user
     * taps a POI on the map.
     */
    override fun onPoiClick(poi: PointOfInterest) {
        val placeId = poi.placeId
        Log.d(TAG, &quot;Place ID: $placeId&quot;)

        // We save the selected place ID to the ViewModel. This is critical for surviving
        // configuration changes. If the user rotates the screen now, the `onCreate`
        // method will be able to restore the place details view.
        viewModel.selectedPlaceId = placeId
        showPlaceDetailsFragment(placeId)
    }

    /**
     * This function is the core of the integration. It creates, configures, and displays
     * the [PlaceDetailsCompactFragment].
     * @param placeId The unique identifier for the place to be displayed.
     */
    private fun showPlaceDetailsFragment(placeId: String) {
        Log.d(TAG, &quot;Showing PlaceDetailsFragment for place ID: $placeId&quot;)

        // We manage the visibility of UI elements to provide feedback to the user.
        // The wrapper is shown, and a loading indicator is displayed while the data is fetched.
        binding.placeDetailsWrapper.visibility = View.VISIBLE
        binding.dismissButton.visibility = View.GONE
        binding.placeDetailsContainer.visibility = View.GONE
        binding.loadingIndicatorMain.visibility = View.VISIBLE

        // The Place Details widget can be displayed vertically or horizontally.
        // We dynamically choose the orientation based on the device&#39;s current configuration.
        val orientation =
            if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                Orientation.HORIZONTAL
            } else {
                Orientation.VERTICAL
            }

        
        // We create a new instance of the fragment using its factory method.
        // We can specify which content to show, the orientation, and a custom theme.
        val fragment = PlaceDetailsCompactFragment.newInstance(
            PlaceDetailsCompactFragment.ALL_CONTENT, // Show all available content.
            orientation,
            R.style.CustomizedPlaceDetailsTheme,
        ).apply {
            // The PlaceLoadListener provides callbacks for when the place data is successfully
            // loaded or when an error occurs. This is where we update our UI state.
            setPlaceLoadListener(object : PlaceLoadListener {
                override fun onSuccess(place: Place) {
                    Log.d(TAG, &quot;Place loaded: ${place.id}&quot;)
                    // Once the data is loaded, we hide the loading indicator and show the fragment.
                    binding.loadingIndicatorMain.visibility = View.GONE
                    binding.placeDetailsContainer.visibility = View.VISIBLE
                    binding.dismissButton.visibility = View.VISIBLE
                }

                override fun onFailure(e: Exception) {
                    Log.e(TAG, &quot;Place failed to load&quot;, e)
                    // On failure, we hide the UI and notify the user.
                    dismissPlaceDetails()
                    Toast.makeText(this@MainActivity, &quot;Failed to load place details.&quot;, Toast.LENGTH_SHORT).show()
                }
            })
        }

        // We add the fragment to our layout&#39;s container view.
        // `commitNow()` is used to ensure the fragment is immediately added and available,
        // which is important because we need to call a method on it right after.
        supportFragmentManager
            .beginTransaction()
            .replace(binding.placeDetailsContainer.id, fragment)
            .commitNow()

        // **This is the key step**: After adding the fragment, we call `loadWithPlaceId`
        // to trigger the data loading process for the selected place.
        // We use `post` to ensure this runs after the layout has been measured,
        // which can prevent potential timing issues.
        binding.root.post {
            fragment.loadWithPlaceId(placeId)
        }
    }


    /**
     * Hides the place details view and clears the selected place ID from the ViewModel.
     */
    private fun dismissPlaceDetails() {
        binding.placeDetailsWrapper.visibility = View.GONE
        // Clearing the ID in the ViewModel is important so that if the user rotates the
        // screen after dismissing, the details view doesn&#39;t reappear.
        viewModel.selectedPlaceId = null
    }

    override fun onDestroy() {
        super.onDestroy()
        // It&#39;s a good practice to nullify references to objects that have a lifecycle
        // tied to the activity, like the GoogleMap object, to prevent potential memory leaks.
        googleMap = null
    }
}
        
  
Conseil : Accédez aux exemples de code complets sur GitHub.

Créer un thème

Lorsque vous instanciez un fragment, vous pouvez spécifier un thème qui remplace l'un des attributs de style par défaut. Tous les attributs de thème qui ne sont pas remplacés utilisent les styles par défaut. Si vous souhaitez prendre en charge un thème sombre, vous pouvez ajouter une entrée pour la couleur dans values-night/colors.xml.

  <style name="CustomizedPlaceDetailsTheme" parent="PlacesMaterialTheme">
    <item name="placesColorPrimary">@color/app_primary_color</item>
    <item name="placesColorOnSurface">@color/app_color_on_surface</item>
    <item name="placesColorOnSurfaceVariant">@color/app_color_on_surface</item>
  
    <item name="placesTextAppearanceBodySmall">@style/app_text_appearence_small</item>
  
    <item name="placesCornerRadius">20dp</item>
  </style>

Utiliser du contenu standard

Cet exemple utilise le contenu standard.

  val fragmentStandardContent = PlaceDetailsCompactFragment.newInstance(
    PlaceDetailsCompactFragment.STANDARD_CONTENT,
    orientation,
    R.style.CustomizedPlaceDetailsTheme
  )

Personnaliser un contenu spécifique

Cet exemple ne sélectionne que les options d'adresse, d'entrée accessible et de média Content pour une vue compacte, et les affiche avec CustomizedPlaceDetailsTheme.

  val placeDetailsFragment = PlaceDetailsCompactFragment.newInstance(
    orientation,
    listOf(
        Content.ADDRESS,
        Content.ACCESSIBLE_ENTRANCE,
        Content.MEDIA
    ),
    R.style.CustomizedPlaceDetailsTheme
)

Utiliser tout le contenu

Cet exemple utilise toutes les options Content d'une vue compacte.

  val fragmentAllContent = PlaceDetailsCompactFragment.newInstance(
    orientation,
    PlaceDetailsCompactFragment.ALL_CONTENT,
    R.style.CustomizedPlaceDetailsTheme
  )