Komponen Place Details tingkat lanjut

Komponen Place Details versi Advanced menawarkan fitur yang sama dengan Place Details Essentials. Anda juga dapat memilih apakah Nama tempat ditampilkan, mengonfigurasi tombol tindakan komponen, dan menerapkan opsi penelusuran dan pemfilteran ke ulasan dan media yang ditampilkan.

Konfigurasi Place Details lanjutan

Gunakan AdvancedPlaceDetailsView atau AdvancedPlaceDetailsCompactView untuk mengakses fitur lanjutan.

Opsi tampilan konten

Anda dapat menentukan konten yang akan ditampilkan menggunakan enum di AdvancedPlaceDetailsContent. Anda dapat mengonfigurasi semua konten yang sama seperti Dasar-Dasar Detail Tempat, serta memilih apakah Nama tempat ditampilkan atau tidak.

Mengonfigurasi tombol tindakan

Gunakan metode .cornerActions dan .mainActions dari AdvancedPlaceDetailsView atau AdvancedPlaceDetailsCompactView untuk menghapus atau menyesuaikan tombol tindakan.

Persyaratan atribusi visual

Tampilan ringkas detail tempat dengan tombol yang disesuaikan
Tampilan ringkas Place Details Lanjutan dengan tombol yang disesuaikan

Penting: Anda harus menjelaskan kepada pengguna akhir kapan tombol tindakan kustom akan membagikan informasi pengguna kepada pihak ketiga selain Google. Lihat persyaratan atribusi visual.

Contoh di sebelah kanan menampilkan gambar kustom yang memperjelas bahwa informasi pengguna akan dikirim ke "Altostrat".

Menerapkan opsi penelusuran dan pemfilteran

Gunakan metode .searchMediaOptions dan .searchReviewOptions dari AdvancedPlaceDetailsView atau AdvancedPlaceDetailsCompactView untuk mengaktifkan penelusuran dan pemfilteran untuk media atau ulasan.

Membuat slot konten kustom

Opsi penempatan slot konten kustom

Slot konten kustom memungkinkan Anda menambahkan konten sendiri (seperti ringkasan buatan AI, stempel waktu itinerari, atau badge kustom) langsung ke zona tata letak yang telah ditentukan.

Untuk menambahkan konten kustom, gunakan metode .placeDetailsCompactContentSlot dari AdvancedPlaceDetailsCompactView. Posisi yang tersedia adalah .basicSectionTop dan .basicSectionBottom.

Persyaratan atribusi dan saran konten untuk slot konten

Saat slot konten kustom dipasang, pengungkapan akan otomatis diperbarui untuk mengklarifikasi konten mana yang disediakan oleh Google dan bahwa beberapa konten disediakan oleh pihak ketiga.

Anjuran

Pertahankan hierarki visual yang jelas antara detail Tempat Google dan konten kustom untuk mencegah ambiguitas tentang sumber informasi.

Mencegah ambiguitas tentang sumber informasi

Anjuran

Pertimbangkan insight bernilai tinggi yang dilokalkan dan disesuaikan dengan tujuan langsung pengguna Anda. Konten yang disesuaikan seperti jendela pemesanan real-time atau ketersediaan saat ini membantu pengguna membuat keputusan yang lebih cepat dan tepat.

Memberikan insight bernilai tinggi

Larangan

Jangan menduplikasi detail Tempat Google yang sudah ada, seperti rating, ulasan, atau jam buka, meskipun Anda telah menyembunyikan konten yang disediakan Google. Tindakan ini dapat membingungkan pengguna tentang sumber konten dan apakah konten tersebut berasal dari Google atau pihak ketiga.

Jangan menduplikasi detail Tempat Google yang sudah ada

Larangan

Jangan menampilkan klaim atau badge tanpa atribusi (misalnya, "Rekomendasi terbaik!") yang dapat disalahartikan sebagai dukungan resmi dari Google. Konten kustom harus secara eksplisit mengatribusikan sumbernya.

Jangan menampilkan klaim atau badge yang tidak memiliki atribusi

Larangan

Jangan sertakan iklan, teks pemasaran, diskon promosi, atau perintah berlangganan dalam penampung tempat kustom.

Jangan sertakan iklan, teks pemasaran, diskon promosi, atau perintah langganan

Contoh Place Details lanjutan

Menghilangkan Nama tempat

Untuk menghilangkan Nama tempat, jangan sertakan .name dalam parameter content dari AdvancedPlaceDetailsConfiguration.

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

Menghapus tombol tindakan

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 []
    }
  }
}

Menambahkan tindakan kustom dan standar

Contoh ini menambahkan opsi bagi pengguna untuk menandai atau membatalkan tanda suatu tempat sebagai favorit, beserta tindakan Buka di Maps yang telah ditentukan sebelumnya.

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

Memfilter ulasan dan media

Contoh kode ini hanya menampilkan media dan ulasan yang menyebutkan "kopi".

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

Membuat slot konten

Contoh ini menambahkan konten ke slot basicSectionTop dan basicSectionBottom.

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