進階 Place Details 元件

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

進階地點詳細資料設定

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

內容顯示選項

您可以使用 AdvancedPlaceDetailsContent 中的列舉,指定要顯示的內容。您可以設定與地點詳細資料基本資訊相同的所有內容,以及選擇是否顯示地點名稱。

設定動作按鈕

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

視覺出處註明規定

顯示地點詳細資料的精簡檢視畫面,並提供自訂按鈕
進階地點詳細資料精簡檢視畫面,附有自訂按鈕

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

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

套用搜尋和篩選選項

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

建立自訂內容插槽

自訂內容插槽刊登位置選項

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

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

內容位置的出處註明規定和內容建議

掛接自訂內容位置時,揭露事項會自動更新,說明哪些內容由 Google 提供,哪些內容由第三方提供。

正確做法

在 Google 地點詳細資料和自訂內容之間維持清楚的視覺階層,避免資訊來源不明。

避免資訊來源不明

正確做法

請考慮提供符合使用者當下目標的在地化實用洞察資料。量身打造的內容 (例如即時預訂時間或目前供應情形) 有助於使用者更快做出更明智的決定。

提供高價值洞察

錯誤做法

即使隱藏了 Google 提供的內容,也不要重複現有的 Google 地點詳細資料,例如評分、評論或營業時間。這麼做可能會讓使用者混淆內容來源,不確定內容是來自 Google 還是第三方。

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

錯誤做法

請勿顯示未標示出處的聲明或徽章 (例如「最佳推薦!」),以免誤導消費者以為是 Google 官方認可。自訂內容必須明確標示來源。

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

錯誤做法

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

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

進階 Place Details 範例

省略地點名稱

如要省略地點名稱,請勿在 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)
      }
    }
}