Erweiterte „Place Details“-Komponente

Die Advanced-Version der Komponente „Place Details“ bietet dieselben Funktionen wie Places Details Essentials. Außerdem können Sie festlegen, ob der Ortsname angezeigt wird, die Aktionsschaltflächen der Komponente konfigurieren und Such- und Filteroptionen auf die angezeigten Rezensionen und Medien anwenden.

Erweiterte Konfiguration von Place Details

Verwende AdvancedPlaceDetailsView oder AdvancedPlaceDetailsCompactView, um auf erweiterte Funktionen zuzugreifen.

Optionen für die Inhaltsanzeige

Mit den Enums in AdvancedPlaceDetailsContent können Sie festlegen, welche Inhalte angezeigt werden sollen. Sie können alle Inhalte wie bei Places Details Essentials konfigurieren und auswählen, ob der Ortsname angezeigt werden soll.

Aktionsschaltflächen konfigurieren

Verwenden Sie die Methoden .cornerActions und .mainActions von AdvancedPlaceDetailsView oder AdvancedPlaceDetailsCompactView, um die Aktionsschaltflächen zu entfernen oder anzupassen.

Anforderungen an die visuelle Quellenangabe

Kompakte Ansicht von Ortsdetails mit benutzerdefinierten Schaltflächen
Kompaktansicht von „Erweiterte Place Details“ mit benutzerdefinierter Schaltfläche

Wichtig:Sie müssen Endnutzern deutlich machen, wenn über eine benutzerdefinierte Aktionsschaltfläche Nutzerinformationen an einen Drittanbieter weitergegeben werden, der nicht Google ist. Weitere Informationen finden Sie unter Anforderungen an die visuelle Quellenangabe.

Im Beispiel rechts ist ein benutzerdefiniertes Bild zu sehen, das verdeutlicht, dass Nutzerinformationen an „Altostrat“ gesendet werden.

Such- und Filteroptionen anwenden

Verwenden Sie die Methoden .searchMediaOptions und .searchReviewOptions von AdvancedPlaceDetailsView oder AdvancedPlaceDetailsCompactView, um die Suche und Filterung von Medien oder Rezensionen zu aktivieren.

Benutzerdefinierte Content-Slots erstellen

Optionen für die Platzierung benutzerdefinierter Inhaltsslots

Mit benutzerdefinierten Inhaltsbereichen können Sie eigene Inhalte wie KI-generierte Zusammenfassungen, Zeitstempel für Routen oder benutzerdefinierte Badges direkt in vordefinierte Layoutbereiche einfügen.

Verwenden Sie zum Hinzufügen benutzerdefinierter Inhalte die Methode .placeDetailsCompactContentSlot von AdvancedPlaceDetailsCompactView. Die verfügbaren Positionen sind .basicSectionTop und .basicSectionBottom.

Anforderungen an die Quellenangabe und Inhaltsempfehlungen für Content-Slots

Wenn ein benutzerdefinierter Inhalts-Slot eingebunden wird, wird der Offenlegungstext automatisch aktualisiert, um zu verdeutlichen, welche Inhalte von Google und welche von Drittanbietern bereitgestellt werden.

Dos

Achten Sie auf eine klare visuelle Hierarchie zwischen den Google-Ortsdetails und benutzerdefinierten Inhalten, damit die Quelle der Informationen eindeutig erkennbar ist.

Unklarheiten bezüglich der Informationsquelle vermeiden

Dos

Bieten Sie lokalisierte, hochwertige Informationen, die auf die unmittelbaren Ziele Ihrer Nutzer zugeschnitten sind. Mit maßgeschneiderten Inhalten wie Echtzeit-Buchungszeiträumen oder der aktuellen Verfügbarkeit können Nutzer schneller fundiertere Entscheidungen treffen.

Wertvolle Statistiken liefern

Nicht erlaubt

Du darfst keine vorhandenen Google-Ortsdetails wie Bewertungen, Rezensionen oder Öffnungszeiten duplizieren, auch wenn du die von Google bereitgestellten Inhalte ausgeblendet hast. Das kann Nutzer verwirren, da sie nicht wissen, ob die Inhalte von Google oder einem Drittanbieter stammen.

Vorhandene Google-Ortsdetails nicht duplizieren

Nicht erlaubt

Sie dürfen keine Behauptungen oder Gütesiegel ohne Quellenangabe (z. B. „Top-Empfehlung!“) anzeigen, die mit offiziellen Empfehlungen von Google verwechselt werden könnten. Bei benutzerdefinierten Inhalten muss die Quelle explizit angegeben werden.

Keine Behauptungen oder Logos ohne Quellenangabe anzeigen

Nicht erlaubt

Benutzerdefinierte Ortscontainer dürfen keine Anzeigen, Marketingtexte, Werberabatte oder Aufforderungen zum Abonnieren enthalten.

Keine Anzeigen, Marketingtexte, Werberabatte oder Aufforderungen zum Abonnieren

Erweiterte Beispiele für „Place Details“

Ortsnamen weglassen

Wenn Sie den Ortsnamen weglassen möchten, geben Sie .name nicht im Parameter content von AdvancedPlaceDetailsConfiguration an.

Swift

struct DemoView: View {
  static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

  // Query for loading the place details component.
  @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
    identifier: .placeID(peetsCoffeePlaceID)
  )
  @State private var favoritePlaces: Set<String> = []

  var body: some View {
    AdvancedPlaceDetailsView(
      query: $query,
      configuration: AdvancedPlaceDetailsConfiguration(
        content:[.address()],
        theme: PlacesMaterialTheme()
      ),
      placeDetailsCallback: { result in
        if let place = result.place {
          print("Place: \(place.description)")
        } else {
          print("Error: \(String(describing: result.error))")
        }
      }
    )
  }
}

Aktionsbuttons entfernen

Swift

struct DemoView: View {
  static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

  @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
    identifier: .placeID(peetsCoffeePlaceID)
  )

  var body: some View {
    AdvancedPlaceDetailsView(
      query: $query,
      configuration: AdvancedPlaceDetailsConfiguration(
        content: AdvancedPlaceDetailsView.allContent,
        theme: PlacesMaterialTheme()
      ),
      placeDetailsCallback: { result in
        if let place = result.place {
          print("Place: \(place.description)")
        } else {
          print("Error: \(String(describing: result.error))")
        }
      }
    )
    .mainActions{ _ in
      return []
    }
  }
}

Benutzerdefinierte und vordefinierte Aktionen hinzufügen

In diesem Beispiel wird eine Option hinzugefügt, mit der Nutzer einen Ort als Favorit markieren oder die Markierung entfernen können. Außerdem wird die vordefinierte Aktion In Maps öffnen verwendet.

Swift

struct DemoView: View {
  static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

  @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
    identifier: .placeID(peetsCoffeePlaceID)
  )
  
  @State var favoritePlaces: Set<String> = []

  var body: some View {
    AdvancedPlaceDetailsView(
      query: $query,
      configuration: AdvancedPlaceDetailsConfiguration(
        content: AdvancedPlaceDetailsView.allContent,
        theme: PlacesMaterialTheme()
      ),
      placeDetailsCallback: { result in
        if let place = result.place {
          print("Place: \(place.description)")
        } else {
          print("Error: \(String(describing: result.error))")
        }
      }
    )
    .mainActions{ place in
      var actions: [MainPlaceActionElement] = []
      let placeID = place.placeID!
      if self.favoritePlaces.contains(placeID) {
        actions.append(
          .action(
            MainPlaceAction(
              image: Image(systemName: "heart.fill"),
              label: "Unfavorite"
            ) { _ in self.toggleFavorite(placeID) }
          )
        )
      } else {
        actions.append(
          .action(
            MainPlaceAction(
              image: Image(systemName: "heart"),
              label: "Favorite"
            ) { _ in self.toggleFavorite(placeID) }
          )
        )
      }
      actions.append(.actionId(.openMap(style: .primary)))
      return actions
    }
    .cornerActions { place in
      var actions: [CornerPlaceActionElement] = []
      let placeID = place.placeID!
      if self.favoritePlaces.contains(placeID) {
        actions.append(
          .action(
            CornerPlaceAction(
              image: Image(systemName: "heart.fill"),
              accessibilityLabel: "Unfavorite",
            ) { _ in self.toggleFavorite(placeID) }
          )
        )
      } else {
        actions.append(
          .action(
            CornerPlaceAction(
              image: Image(systemName: "heart"),
              accessibilityLabel: "Favorite",
            ) { _ in self.toggleFavorite(placeID) }
          )
        )
      }
      actions.append(.actionId(.openMap(style: .primary)))
      return actions
    }
  }

  func toggleFavorite(_ placeID: String) {
    if favoritePlaces.contains(placeID) {
      favoritePlaces.remove(placeID)
    } else {
      favoritePlaces.insert(placeID)
    }
  }
}

Rezensionen und Medien filtern

In diesem Codebeispiel werden nur Medien und Rezensionen angezeigt, in denen „Kaffee“ erwähnt wird.

Swift

struct DemoView: View {
  static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

  @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
    identifier: .placeID(peetsCoffeePlaceID)
  )
  let searchMediaOptions = SearchMediaOptions(query: "coffee")
  let searchReviewsOptions = SearchReviewsOptions(query: "coffee")

  var body: some View {
    AdvancedPlaceDetailsView(
      query: $query,
      configuration: AdvancedPlaceDetailsConfiguration(
        content: [.media(), .reviews()],
        theme: PlacesMaterialTheme()
      ),
      placeDetailsCallback: { _ in }
    )
    .searchMediaOptions(searchMediaOptions) { results in
      guard let result = results.first else { return }
      switch result {
      case .success(let summary):
        print("Summary: \(summary)")
      case .failure(let error):
        print("Error: \(error)")
      }
    }
    .searchReviewsOptions(searchReviewsOptions) { results in
      guard let result = results.first else { return }
      switch result {
      case .success(let summary):
        print("Summary: \(summary)")
      case .failure(let error):
        print("Error: \(error)")
      }
    }
  }
}

Content-Slots erstellen

In diesem Beispiel werden den Slots basicSectionTop und basicSectionBottom Inhalte hinzugefügt.

Swift

import SwiftUI
import PlacesSwift

struct ItineraryCard: View {
    static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

    @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
      identifier: .placeID(peetsCoffeePlaceID)
    )

    var body: some View {
      AdvancedPlaceDetailsCompactView(
        orientation: .vertical,
        query: $query,
        configuration: AdvancedPlaceDetailsCompactConfiguration(
          content: AdvancedPlaceDetailsCompactView.allContent,
          theme: PlacesMaterialTheme()
        ),
        placeDetailsCallback: { _ in }
      )
      .placeDetailsCompactContentSlot(position: .basicSectionTop) { place in
        Text("Day 2 • 2:30 PM")
          .font(.caption)
          .fontWeight(.bold)
          .foregroundColor(.accentColor)
      }
      .placeDetailsCompactContentSlot(position: .basicSectionBottom) { place in
        VStack(alignment: .leading, spacing: 4) {
          Text("AI Notes")
            .font(.caption)
            .bold()
          Text("Great quiet atmosphere for morning meetings. Famous for house-roasted pour-overs.")
            .font(.footnote)
            .foregroundColor(.secondary)
        }
        .padding(8)
        .background(Color(.systemGray6))
        .cornerRadius(8)
      }
    }
}