進階 Place Details 元件

Place Details 元件的 Advanced 版本提供與 Places Details Essentials 相同的功能。您也可以選擇是否顯示地點名稱、設定元件的動作按鈕,以及對顯示的評論和媒體套用搜尋和篩選選項。

進階 Place Details 設定

使用 AdvancedPlaceDetailsView 或 AdvancedPlaceDetailsCompactView 存取進階功能。

內容顯示選項

您可以使用 AdvancedPlaceDetailsContent 中的列舉,指定要顯示的內容。您可以設定與Place Details Essentials相同的所有內容,以及選擇是否顯示地點名稱。

設定動作按鈕

使用 AdvancedPlaceDetailsView 或 AdvancedPlaceDetailsCompactView 的 .cornerActions 和 .mainActions 方法,移除或自訂動作按鈕。

視覺出處規定

地點詳細資料精簡檢視畫面,含自訂按鈕
進階 Place Details 精簡檢視畫面,含自訂按鈕

重要事項:如果自訂動作按鈕會將使用者資訊分享給 Google 以外的第三方,請務必向使用者清楚說明。請參閱視覺出處註明規定。

右側範例顯示的自訂圖片,清楚說明使用者資訊將傳送至「Altostrat」。

套用搜尋和篩選選項

使用 AdvancedPlaceDetailsView 或 AdvancedPlaceDetailsCompactView 的 .searchMediaOptions 和 .searchReviewOptions 方法,啟用媒體或評論的搜尋和篩選功能。

建立自訂內容版位

自訂內容版位刊登位置選項

自訂內容版位可讓您直接在預先定義的版面配置區域中,加入自己的內容 (例如 AI 生成的摘要、行程時間戳記或自訂徽章)。

如要新增自訂內容,請使用 AdvancedPlaceDetailsCompactView 的 .placeDetailsCompactContentSlot 方法。可用的位置為 .basicSectionTop 和 .basicSectionBottom。

內容版位的出處規定和內容建議

掛接自訂內容版位時,揭露聲明會自動更新,說明哪些內容由 Google 提供,以及部分內容由第三方提供。

正確做法

Google 地點詳細資料和自訂內容之間,應維持清楚的視覺階層結構,避免資訊來源混淆。

避免資訊來源不明

正確做法

建議提供本地化的高價值深入分析,滿足使用者當下的目標。即時預訂時段或目前空房情況等量身打造的內容,可協助使用者更快做出更明智的決策。

提供高價值洞察

錯誤做法

請勿複製現有的 Google Place Details,例如評分、評論或營業時間,即使您已隱藏 Google 提供的內容也一樣。否則使用者可能會混淆內容來源,不確定是來自 Google 還是第三方。

請勿複製現有的 Google 地點詳細資料

錯誤做法

請勿顯示未註明出處的聲明或徽章 (例如「首選推薦!」),以免使用者誤以為是 Google 官方背書。自訂內容必須明確註明來源。

請勿顯示未註明出處的聲明或徽章

錯誤做法

請勿在自訂地點容器中加入廣告、行銷文案、促銷折扣或訂閱提示。

請勿加入廣告、行銷文案、促銷折扣或訂閱提示

Place Details (Advanced) 範例

省略地點名稱

如要省略地點名稱,請勿在 AdvancedPlaceDetailsConfiguration 的 content 參數中加入 .name。

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

移除動作按鈕

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

新增自訂和預先定義的動作

這個範例會新增一個選項,讓使用者將地點加入或取消收藏,並提供預先定義的「在 Google 地圖中開啟」動作。

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

篩選評論和媒體

這個程式碼範例只會顯示提及「咖啡」的媒體和評論。

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

建立內容版位

這個範例會將內容新增至 basicSectionTop 和 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)
      }
    }
}