Android 09.1 進階功能:Google 地圖

1. 歡迎

這個程式碼研究室是 Google Developers 訓練團隊開發的進階 Android 開發訓練課程的一部分。建議您依序完成程式碼研究室,充分體驗本課程的價值。

如要查看課程的完整詳細資料,請參閱進階 Android 開發課程總覽

簡介

使用 Google 地圖建構應用程式時,您可以為應用程式新增衛星圖像、強大的 UI 控制項、位置追蹤和地點標記等功能。您可以顯示自有資料集中的資訊 (例如知名釣魚或攀岩地點),為標準 Google 地圖增添價值。您也可以建立與現實世界相關的遊戲,例如《Pokemon Go》。

在本實作練習中,您會建立名為 Wander 的 Google 地圖應用程式。

必備知識

您必須已經熟悉下列項目:

  • Google 地圖的基本功能。
  • 執行階段權限。
  • 在 Android Studio 中建立、建構及執行應用程式。
  • build.gradle 檔案中加入外部程式庫。

課程內容

  • 在應用程式中整合 Google 地圖。
  • 顯示不同地圖類型。
  • 設定 Google 地圖樣式。
  • 在地圖中加入標記。
  • 讓使用者在搜尋點上放置標記。
  • 啟用位置追蹤功能。
  • 啟用 Google 街景服務。

學習內容

  • 從 Google API 控制台取得 API 金鑰,並向應用程式註冊該金鑰。
  • 建立內嵌 Google 地圖的 Wander 應用程式。
  • 在應用程式中加入標記、樣式和位置追蹤等自訂功能。
  • 在應用程式中啟用位置追蹤和街景服務。

2. 應用程式總覽

在本實作練習中,您會建立 Wander 應用程式,也就是經過樣式設定的 Google 地圖。使用 Wander 應用程式,您可以在地圖上放置標記、即時查看自己的位置,以及查看街景服務全景。

樣式化 Google 地圖

Android 應用程式中的 Google 街景服務

3. 工作 1:設定專案並取得 API 金鑰

Google Maps API (例如 Places API) 需要 API 金鑰。如要取得 API 金鑰,請在 Google API 控制台中註冊專案。API 金鑰會繫結至數位憑證,將應用程式連結至作者。如要進一步瞭解如何使用數位憑證及簽署應用程式,請參閱「簽署應用程式」。

在本實作練習中,您將使用偵錯憑證的 API 金鑰。如「簽署偵錯版本」一文所述,偵錯憑證的設計本來就不安全,使用 Google Maps API 發布的 Android 應用程式需要第二個 API 金鑰,也就是發布憑證的金鑰。如要進一步瞭解如何取得發布憑證,請參閱「取得 API 金鑰」。

Android Studio 內含 Google 地圖活動範本,可產生實用的範本程式碼。範本程式碼包含 google_maps_api.xml 檔案,內含可簡化 API 金鑰取得流程的連結。

1.1 使用地圖範本建立 Wander 專案

  1. 建立新的 Android Studio 專案。
  2. 將新應用程式命名為「Wander」。接受預設值,直到進入「新增活動」頁面。
  3. 選取「Google 地圖活動」範本。
  4. 保留預設的「Activity Name」和「Layout Name」
  5. 將「Title」變更為「Wander」,然後按一下「Finish」

Android Studio 會建立多個與地圖相關的額外檔案:

google_maps_api**.xml**

您可以使用這個設定檔保存 API 金鑰。範本會產生兩個 google_maps_api.xml 檔案,分別用於偵錯和發布。偵錯憑證的 API 金鑰檔案位於 src/debug/res/values。發布憑證的 API 金鑰檔案位於 src/release/res/values 中。在本實作練習中,我們只會使用偵錯憑證。

activity_maps.xml

這個版面配置檔案包含填滿整個畫面的單一片段。SupportMapFragment 類別是 Fragment 類別的子類別。您可以在任何 ViewGroup 中使用 <fragment> 標記,在版面配置檔案中加入 SupportMapFragment,並使用額外屬性:

android:name="com.google.android.gms.maps.SupportMapFragment"

MapsActivity.java

MapsActivity.java 檔案會例項化 SupportMapFragment 類別,並使用該類別的 getMapAsync() 方法準備 Google 地圖。包含 SupportMapFragment 的活動必須實作 OnMapReadyCallback 介面和該介面的 onMapReady() 方法。getMapAsync() 方法會傳回 GoogleMap 物件,表示地圖已載入。

1.2 取得 API 金鑰

  1. 開啟 google_maps_api.xml 檔案的偵錯版本。

檔案包含含有長網址的註解。網址參數包含應用程式的特定資訊。

  1. 複製網址並貼到瀏覽器中。
  2. 按照提示在 Google API 控制台建立專案。由於提供的網址中含有參數,API 控制台會自動啟用 Google 地圖 Android API
  3. 建立 API 金鑰,然後按一下「限制金鑰」,將金鑰的使用限制在 Android 應用程式。產生的 API 金鑰應以 AIza 開頭。
  4. google_maps_api.xml 檔案中,將金鑰貼到 google_maps_key 字串中標示 YOUR_KEY_HERE 的位置。
  5. 執行應用程式。您會在活動中看到內嵌地圖,並在澳洲雪梨設定標記。(雪梨標記是範本的一部分,您稍後可以變更)。

4. 工作 2:新增地圖類型和標記

Google 地圖提供多種地圖類型,包括一般、混合、衛星、地形和「無」。在這項工作中,您會新增應用程式列和選項選單,讓使用者變更地圖類型。將地圖的起始位置移至住家位置。接著,您要新增標記的支援功能,標記是用來標出地圖上的某個位置,並可包含標籤。

2.1 新增地圖類型

使用者需要的地圖類型取決於他們需要的資訊。在車上使用地圖導航時,清楚顯示街道名稱會很有幫助。在登山時,你可能更關心要爬多高才能抵達山頂。在這個步驟中,您會新增應用程式列和選項選單,讓使用者變更地圖類型。

  1. 如要建立新的選單 XML 檔案,請在 res 目錄上按一下滑鼠右鍵,然後選取「New」>「Android Resource File」
  2. 在對話方塊中,將檔案命名為 map_options。選擇資源類型的「選單」。然後點選「OK」
  3. 將新檔案中的程式碼替換成下列程式碼,建立地圖選項。系統會省略「無」地圖類型,因為「無」會導致完全沒有地圖。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item android:id="@+id/normal_map"
       android:title="@string/normal_map"
       app:showAsAction="never"/>
   <item android:id="@+id/hybrid_map"
       android:title="@string/hybrid_map"
       app:showAsAction="never"/>
   <item android:id="@+id/satellite_map"
       android:title="@string/satellite_map"
       app:showAsAction="never"/>
   <item android:id="@+id/terrain_map"
       android:title="@string/terrain_map"
       app:showAsAction="never"/>
</menu>
  1. title 屬性建立字串資源。
  2. MapsActivity 檔案中,將類別變更為擴充 AppCompatActivity 類別,而非擴充 FragmentActivity 類別。使用 AppCompatActivity 會顯示應用程式列,因此也會顯示選單。
  3. MapsActivity 中,覆寫 onCreateOptionsMenu() 方法並擴充 map_options 檔案:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
   MenuInflater inflater = getMenuInflater();
   inflater.inflate(R.menu.map_options, menu);
   return true;
}
  1. 如要變更地圖類型,請對 GoogleMap 物件使用 setMapType() 方法,並傳遞其中一個地圖類型常數。

覆寫 onOptionsItemSelected() 方法。貼上下列程式碼,在使用者選取其中一個選單選項時變更地圖類型:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
       // Change the map type based on the user's selection.
       switch (item.getItemId()) {
           case R.id.normal_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
               return true;
           case R.id.hybrid_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
               return true;
           case R.id.satellite_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
               return true;
           case R.id.terrain_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
               return true;
           default:
               return super.onOptionsItemSelected(item);
       }
    }
  1. 執行應用程式。使用應用程式列中的選單變更地圖類型。請注意地圖外觀的變化。

2.2 移動預設地圖位置

根據預設,onMapReady() 回呼包含的程式碼會在 Google 地圖的建立地點 (澳洲雪梨) 放置標記。預設回呼也會將地圖動畫設為平移至雪梨。在這個步驟中,您會將地圖平移至住家位置,但不放置標記,然後縮放至您指定的等級。

  1. onMapReady() 方法中,移除在雪梨放置標記並移動攝影機的程式碼。
  2. 在瀏覽器中前往 www.google.com/maps,然後找出住家。
  3. 在該位置上按一下滑鼠右鍵,然後選取「這是哪裡?」

畫面底部會彈出小視窗,顯示位置資訊,包括經緯度。

  1. 建立名為 home 的新 LatLng 物件。在 LatLng 物件中,使用您在瀏覽器中從 Google 地圖找到的座標。
  2. 建立名為 zoomfloat 變數,並將變數設為所需的初始縮放等級。以下清單列出各縮放等級大致可顯示的精細程度:
  • 1:全球
  • 5:陸地/大陸
  • 10:城市
  • 15:街道
  • 20:建築物
  1. 使用 CameraUpdateFactory.newLatLngZoom() 建立 CameraUpdate 物件,並傳入 LatLng 物件和 zoom 變數。呼叫 GoogleMap 物件的 moveCamera(),並傳入新的 CameraUpdate 物件,即可平移及縮放鏡頭:
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(home, zoom));
  1. 執行應用程式。地圖應會平移至住家位置,並縮放至所需等級。

2.3 新增地圖標記

Google 地圖可使用標記標示出特定位置,標記是使用 Marker 類別建立。預設標記會使用標準的 Google 地圖圖示:Google 地圖標記

您可以擴充標記,在資訊視窗中顯示背景資訊。

在這個步驟中,您會在使用者觸控並按住地圖上的位置時新增標記。接著,您會新增 InfoWindow,在輕觸標記時顯示標記的座標。

掉落圖釘的資訊視窗

  1. MapsActivity 中建立名為 setMapLongClick() 的方法存根,該方法會將 final GoogleMap 做為引數,並傳回 void
private void setMapLongClick(final GoogleMap map) {}
  1. 使用 GoogleMap 物件的 setOnMapLongClickListener() 方法,在使用者觸控並按住的位置放置標記。傳遞 OnMapLongClickListener 的新例項,覆寫 onMapLongClick() 方法。傳入的引數是 LatLng 物件,其中包含使用者按下位置的座標:
private void setMapLongClick(final GoogleMap map) {
   map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
       @Override
       public void onMapLongClick(LatLng latLng) {
       }
   });
}
  1. onMapLongClick() 中呼叫 addMarker() 方法。傳入新的 MarkerOptions 物件,並將位置設為傳入的 LatLng
map.addMarker(new MarkerOptions().position(latLng));
  1. onMapReady() 方法結尾呼叫 setMapLongClick()。傳入 mMap
  2. 執行應用程式,然後按住地圖,在某個位置放置標記。
  3. 輕觸標記,將其置中顯示在畫面上。

畫面左下角會顯示導覽按鈕,方便使用者透過 Google 地圖應用程式導覽至標記位置。

如要為標記新增資訊視窗,請按照下列步驟操作:

  1. MarkerOptions 物件中,設定 title 欄位和 snippet 欄位。
  2. onMapLongClick() 中,將 title 欄位設為「Dropped Pin」(已放置的圖釘)。在 addMarker() 方法中,將 snippet 欄位設為位置座標。
map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
   @Override
   public void onMapLongClick(LatLng latLng) {
       String snippet = String.format(Locale.getDefault(),
               "Lat: %1$.5f, Long: %2$.5f",
               latLng.latitude,
               latLng.longitude);

       map.addMarker(new MarkerOptions()
               .position(latLng)
               .title(getString(R.string.dropped_pin))
               .snippet(snippet));
   }
});
  1. 執行應用程式,然後按住地圖放置位置標記。輕觸標記即可顯示資訊視窗。

2.4 新增搜尋點監聽器

根據預設,地圖上會顯示搜尋點和對應的圖示。搜尋點包括公園、學校、政府大樓等。如果地圖類型設為 normal,地圖上也會顯示商家搜尋點。商家搜尋點代表商家,例如商店、餐廳和飯店。

在這個步驟中,您會在 Google 地圖中新增 GoogleMap.OnPoiClickListener。這個點擊事件監聽器會立即在地圖上放置標記,不必等待觸控並按住。點擊事件監聽器也會顯示包含 POI 名稱的資訊視窗。

搜尋點標記

  1. MapsActivity 中建立名為 setPoiClick() 的方法存根,將 final GoogleMap 做為引數,並傳回 void
private void setPoiClick(final GoogleMap map) {}
  1. setPoiClick() 方法中,針對傳入的 GoogleMap 設定 OnPoiClickListener
map.setOnPoiClickListener(new GoogleMap.OnPoiClickListener() {
   @Override
   public void onPoiClick(PointOfInterest poi) {
   }
});
  1. onPoiClick() 方法中,將標記放在 POI 位置。將標題設為地標名稱。將結果儲存至名為 poiMarker 的變數。
public void onPoiClick(PointOfInterest poi) {
   Marker poiMarker = mMap.addMarker(new MarkerOptions()
       .position(poi.latLng)
       .title(poi.name);
}
  1. poiMarker 上呼叫 showInfoWindow(),即可立即顯示資訊視窗。
poiMarker.showInfoWindow();
  1. onMapReady() 結尾呼叫 setPoiClick()。傳入 mMap
  2. 執行應用程式,然後尋找公園等 POI。輕觸 POI 即可在該位置放置標記,並在資訊視窗中顯示 POI 名稱。

5. 工作 3:設定地圖樣式

你可以透過多種方式自訂 Google 地圖,打造獨特的外觀和風格。

您可以透過可用的 XML 屬性自訂 MapFragment 物件,就像自訂任何其他片段一樣。不過,在這個步驟中,您將使用 GoogleMap 物件的方法,自訂 MapFragment內容外觀和風格。您可以使用線上樣式精靈,在地圖中新增樣式及自訂標記。您也可以在住家位置新增 GroundOverlay,並隨著地圖縮放及旋轉。

3.1 在地圖中新增樣式

如要為地圖建立自訂樣式,請產生 JSON 檔案,指定地圖中顯示的特徵。您不必手動建立這個 JSON 檔案,Google 提供的樣式精靈會在您設定地圖樣式後,自動產生 JSON 檔案。在本實作練習中,您將為「夜間模式」設定地圖樣式,也就是讓地圖使用暗色和低對比度,方便夜間使用。

  1. 在瀏覽器中前往 https://mapstyle.withgoogle.com/
  2. 選取「建立樣式」
  3. 選取「夜間」主題。
  4. 按一下選單底部的「更多選項」
  5. 在「地圖項目類型」清單底部,依序選取「水域」>「填滿」。將水域顏色變更為深藍色 (例如 #160064)。
  6. 按一下「完成」。從產生的彈出式視窗複製 JSON 程式碼。
  7. 在 Android Studio 中,於 res 目錄中建立名為 raw 的資源目錄。在 res/raw 中建立名為 map_style.json 的檔案。
  8. 將 JSON 程式碼貼到新的資源檔案中。
  9. 如要將 JSON 樣式設為地圖,請對 GoogleMap 物件呼叫 setMapStyle()。傳遞 MapStyleOptions 物件,載入 JSON 檔案。setMapStyle() 方法會傳回布林值,指出樣式設定是否成功。如果無法載入檔案,這個方法會擲回 Resources.NotFoundException

將下列程式碼複製到 onMapReady() 方法中,即可設定地圖樣式。您可能需要為記錄陳述式建立 TAG 字串:

     try {
        // Customize the styling of the base map using a JSON object defined
        // in a raw resource file.
        boolean success = googleMap.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
                   this, R.raw.map_style));

        if (!success) {
            Log.e(TAG, "Style parsing failed.");
        }
     } catch (Resources.NotFoundException e) {
        Log.e(TAG, "Can't find style. Error: ", e);
     }
  1. 執行應用程式。地圖處於 normal 模式時,應該會顯示新樣式。

夜間模式樣式的 Google 地圖

3.2 設定標記樣式

您可以進一步自訂地圖標記的樣式,打造個人專屬地圖。在這個步驟中,您會變更預設的紅色標記,使其符合夜間模式的色彩配置。

  1. onMapLongClick() 方法中,將下列程式碼行新增至 MarkerOptions() 建構函式,即可使用預設標記,但將顏色變更為藍色:
.icon(BitmapDescriptorFactory.defaultMarker
       (BitmapDescriptorFactory.HUE_BLUE))
  1. 執行應用程式。現在,您放置的標記會以藍色陰影顯示,與應用程式的夜間模式主題更一致。

請注意,搜尋點標記仍為紅色,因為您未在 onPoiClick() 方法中新增樣式。

3.3 新增疊加層

自訂 Google 地圖的方法之一,就是在地圖上繪製內容。如果您想強調特定類型的地點 (例如熱門釣魚地點),這個技巧就十分實用。支援的重疊類型有三種:

  • 形狀:您可以在地圖上新增折線多邊形圓形
  • TileOverlay 物件:圖塊疊加層會定義疊加在基本地圖圖塊上的一組圖像。當您想在地圖上加入大量圖像時,圖塊疊加層就非常實用。一般來說,圖塊疊加層涵蓋的地理區域範圍很廣。
  • GroundOverlay 物件:區域疊加層是指固定於地圖上的圖片。不同於標記,區域疊加層的顯示方向是依據實際地表而非裝置螢幕。旋轉、傾斜或縮放地圖時,圖片的方向也會隨之改變。當您想修正地圖上某個區域的單一圖片時,區域疊加層就非常實用

在這個步驟中,您會在住家位置新增 Android 形狀的地面疊加層。

  1. 下載這個 Android 映像檔,並儲存在 res/drawable 資料夾中。
  2. onMapReady() 中,呼叫將攝影機移至初始位置後,請建立 GroundOverlayOptions 物件。將物件指派給名為 homeOverlay 的變數:
GroundOverlayOptions homeOverlay = new GroundOverlayOptions();
  1. 使用 BitmapDescriptorFactory.fromResource() 方法,從上述圖片建立 BitmapDescriptor 物件。將物件傳遞至 GroundOverlayOptions 物件的 image() 方法:
GroundOverlayOptions homeOverlay = new GroundOverlayOptions()
    .image(BitmapDescriptorFactory.fromResource(R.drawable.android));
  1. 呼叫 position() 方法,為 GroundOverlayOptions 物件設定 position 屬性。傳遞 home LatLng 物件和 float,以指定所需疊加層的寬度 (以公尺為單位)。在這個範例中,100 公尺的寬度很合適:
GroundOverlayOptions homeOverlay = new GroundOverlayOptions()
     .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
       .position(home, 100);
  1. GoogleMap 物件呼叫 addGroundOverlay()。傳入 GroundOverlayOptions 物件:
mMap.addGroundOverlay(homeOverlay);
  1. 執行應用程式。放大住家位置,您會看到 Android 圖片疊加在上面。

6. 工作 4:啟用位置追蹤和街景服務

使用者經常使用 Google 地圖查看目前位置,您可以透過 Location Services API 取得裝置位置。如要在地圖上顯示裝置位置,但不想進一步使用 Location 資料,可以使用位置資料圖層

位置資料圖層會在右上角的地圖中新增「我的位置」按鈕。使用者輕觸按鈕後,地圖會以裝置所在位置為中心。如果裝置未移動,地圖上會以藍點標示位置;如果裝置正在移動,則會顯示為藍色箭號圖示。

已啟用位置追蹤功能的樣式化 Google 地圖

你可以使用 Google 街景服務提供地點的其他相關資訊。這項服務提供特定地點的可瀏覽全景相片。

在這項工作中,您會啟用位置資料圖層和街景服務,讓使用者輕觸地標標記的資訊視窗時,地圖會進入街景服務模式。

4.1 啟用位置追蹤功能

如要在 Google 地圖中啟用位置資訊追蹤功能,只需要一行程式碼。不過,您必須確保使用者已授予位置資訊權限 (使用執行階段權限模型)。

在這個步驟中,您會要求位置存取權,並啟用位置追蹤功能。

  1. AndroidManifest.xml 檔案中,確認是否已存在 FINE_LOCATION 權限。選取 Google 地圖範本時,Android Studio 會插入這項權限。
  2. 如要在應用程式中啟用位置資訊追蹤功能,請在 MapsActivity 中建立名為 enableMyLocation() 的方法,這個方法不採用任何引數,且不會傳回任何內容。
  3. 定義 enableMyLocation() 方法。檢查 ACCESS_FINE_LOCATION 權限。如果授予權限,請啟用位置資訊圖層。否則請要求權限:
private void enableMyLocation() {
   if (ContextCompat.checkSelfPermission(this,
           Manifest.permission.ACCESS_FINE_LOCATION)
           == PackageManager.PERMISSION_GRANTED) {
       mMap.setMyLocationEnabled(true);
   } else {
       ActivityCompat.requestPermissions(this, new String[]
                       {Manifest.permission.ACCESS_FINE_LOCATION},
               REQUEST_LOCATION_PERMISSION);
   }
}
  1. onMapReady() 回呼呼叫 enableMyLocation(),即可啟用位置資訊圖層。
  2. 覆寫 onRequestPermissionsResult() 方法。如果已授予權限,請呼叫 enableMyLocation()
@Override
public void onRequestPermissionsResult(int requestCode,
       @NonNull String[] permissions,
       @NonNull int[] grantResults) {
   // Check if location permissions are granted and if so enable the
   // location data layer.
   switch (requestCode) {
       case REQUEST_LOCATION_PERMISSION:
           if (grantResults.length > 0
                   && grantResults[0]
                   == PackageManager.PERMISSION_GRANTED) {
               enableMyLocation();
               break;
           }
   }
}
  1. 執行應用程式。右上角現在會顯示「我的位置」按鈕,可顯示裝置目前位置。

4.2 啟用街景服務

Google 地圖提供街景服務,可顯示地點的全景,並提供沿指定路徑導覽的控制項。街景服務並未涵蓋全球

在本步驟中,您將啟用街景服務全景,使用者輕觸地標的資訊視窗時,系統就會啟動這項全景。請務必完成以下兩個動作:

  1. 將搜尋點標記與其他標記區分開來,因為您希望應用程式的功能適用於搜尋點標記。這樣一來,使用者輕觸搜尋點資訊視窗時,您就能啟動街景服務,但使用者輕觸任何其他類型的標記時,則不會啟動街景服務。

Marker 類別包含 setTag() 方法,可讓您附加資料。(資料可以是從 Object 擴充的任何內容)。您會在使用者點選搜尋點時建立的標記上設定標記。

  1. 使用者輕觸 OnInfoWindowClickListener 中已加上標記的資訊視窗時,請將 MapFragment 替換為 StreetViewPanoramaFragment。(下方程式碼使用 SupportMapFragmentSupportStreetViewPanoramaFragment,支援 API 12 以下的 Android 版本)。

如果任何片段在執行階段發生變化,您必須在包含的 Activity 類別中新增片段,而不是在 XML 中靜態新增。

標記搜尋點標記

  1. onPoiClick() 回呼中,對 poiMarker 呼叫 setTag()。傳遞任意字串:
poiMarker.setTag("poi");

將靜態 SupportMapFragment 替換為執行階段執行個體

  1. 開啟 activity_maps.xml,並將元素變更為要做為片段容器的影格版面配置:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/fragment_container"
   android:layout_width="match_parent"
   android:layout_height="match_parent" />
  1. MapsActivityonCreate() 中,移除依 ID 尋找 SupportMapFragment 的程式碼,因為 XML 中不再有靜態 SupportMapFragment。請改為呼叫 SupportMapFragment.newInstance(),建立 SupportMapFragment 的新執行階段例項:
SupportMapFragment mapFragment = SupportMapFragment.newInstance();
  1. 使用含有 FragmentManager 的片段交易,將片段新增至 FrameLayout
getSupportFragmentManager().beginTransaction()
       .add(R.id.fragment_container, mapFragment).commit();
  1. 保留觸發地圖非同步載入的程式碼行:
mapFragment.getMapAsync(this);

設定 OnInfoWindowClickListener 並檢查標記代碼

  1. MapsActivity 中建立名為 setInfoWindowClickToPanorama() 的方法存根,該方法會將 GoogleMap 做為引數,並傳回 void
private void setInfoWindowClickToPanorama(GoogleMap map) {}
  1. OnInfoWindowClickListener 設為 GoogleMap
map.setOnInfoWindowClickListener(
       new GoogleMap.OnInfoWindowClickListener() {
           @Override
           public void onInfoWindowClick(Marker marker) {
           }
       });
  1. onInfoWindowClick() 方法中,檢查標記是否包含您在 onPoiClick() 方法中設定的字串標記:
if (marker.getTag() == "poi") {}

將 SupportMapFragment 替換為 SupportStreetViewPanoramaFragment

  1. 如果標記含有標記,請使用 StreetViewPanoramaOptions 物件指定街景服務全景的位置。將物件的 position 屬性設為傳入的標記位置:
StreetViewPanoramaOptions options =
       new StreetViewPanoramaOptions().position(
               marker.getPosition());
  1. 建立 SupportStreetViewPanoramaFragment 的新例項,並傳入您建立的 options 物件:
SupportStreetViewPanoramaFragment streetViewFragment
       = SupportStreetViewPanoramaFragment
       .newInstance(options);
  1. 開始片段交易。將片段容器的內容替換為新片段 streetViewFragment。將交易新增至返回堆疊,這樣按下返回鍵時,系統就會返回 SupportMapFragment,而不是結束應用程式:
getSupportFragmentManager().beginTransaction()
       .replace(R.id.fragment_container,
               streetViewFragment)
       .addToBackStack(null).commit();
  1. 在呼叫 setPoiClick(). 後,於 onMapReady() 中呼叫 setInfoWindowClickToPanorama(mMap)
  2. 執行應用程式。縮放至街景服務涵蓋範圍內的城市,例如 Google 總部所在地 Mountain View,然後找出 POI,例如公園。輕觸 POI 即可放置標記並顯示資訊視窗。輕觸資訊視窗,即可進入標記位置的街景模式。按下返回鍵,返回地圖片段。

Android 應用程式中的 Google 街景服務

7. 解決方案程式碼

Wander 解決方案程式碼。

8. 程式設計挑戰

挑戰:如果輕觸沒有街景服務涵蓋範圍的地點資訊視窗,畫面會顯示黑色。

9. 摘要

  • 如要使用 Maps API,您需要透過 Google API 控制台取得 API 金鑰。
  • 在 Android Studio 中,使用 Google 地圖活動範本會產生 Activity,其中包含應用程式版面配置中的單一 SupportMapFragment。範本也會將 ACCESS_FINE_PERMISSION 新增至應用程式資訊清單、在活動中實作 OnMapReadyCallback,並覆寫必要的 onMapReady() 方法。

如要在執行階段變更 GoogleMap 的地圖類型,請使用 GoogleMap.setMapType() 方法。Google 地圖可以是下列任一類型:

  • 一般:一般道路地圖。顯示道路、部分人造設施,以及河流等重要自然景觀,Road and feature labels are also visible.
  • 混合:加入道路地圖的衛星相片資料,Road and feature labels are also visible.
  • 衛星:相片資料。不顯示道路和地圖項目標籤。
  • 地形:地形資料。該地圖包含的顏色,輪廓線和標籤,和透視陰影。也顯示部分道路和地圖項目標籤。
  • **:** 不顯示地圖。

關於 Google 地圖:

  • 「標記」是特定地理位置的指標。
  • 輕觸標記時,系統預設會顯示資訊視窗,內含位置資訊。
  • 根據預設,搜尋點會與其對應的圖示一併顯示在基本地圖上。搜尋點包括公園、學校、政府大樓等。
  • 此外,如果地圖類型為 normal,預設會顯示商家搜尋點 (商店、餐廳、飯店等)。
  • 您可以使用 OnPoiClickListener 擷取搜尋點上的點擊動作。
  • 您可以使用樣式精靈,變更 Google 地圖上幾乎所有元素的外觀。樣式精靈會產生 JSON 檔案,您可以使用 setMapStyle() 方法將該檔案傳遞至 Google 地圖。
  • 您可以變更標記的預設顏色或圖示圖片,自訂屬於自己的標記。

其他重要資訊:

  • 使用區域疊加層將圖片固定在地理位置上。
  • 使用 GroundOverlayOptions 物件指定圖片、圖片大小 (以公尺為單位) 和圖片位置。將這個物件傳遞至 GoogleMap.addGroundOverlay() 方法,即可在地圖上設定疊加層。
  • 只要應用程式具備 ACCESS_FINE_LOCATION 權限,您就能使用 mMap.setMyLocationEnabled(true) 方法啟用位置追蹤功能。
  • 使用 Google 街景服務可在指定道路的涵蓋區域,進行 360 度全景檢視。
  • 使用 StreetViewPanoramaFragment.newInstance() 方法建立新的街景片段。
  • 如要指定檢視畫面選項,請使用 StreetViewPanoramaOptions 物件。將物件傳遞至 newInstance() 方法。

10. 瞭解詳情

相關概念說明文件請參閱 9.1:Google 地圖 API

Android 開發人員說明文件:

參考說明文件:

11. 作業

本節列出的作業可由課程講師指派給學習本程式碼研究室的學員。講師可自由採取以下行動:

  • 視需要指派作業。
  • 告知學員如何繳交作業。
  • 為作業評分。

講師可以視需求使用全部或部分建議內容,也可以自由指派任何其他合適的作業。

如果您是自行學習本程式碼研究室,不妨利用這些作業驗收學習成果。

建構並執行應用程式

  1. 建立使用 Google 地圖活動範本的新應用程式,在應用程式啟動時載入 Google 地圖。
  2. 載入 Google 地圖後,將攝影機移至學校、住家或其他對您有意義的地點。
  3. 在地圖上新增兩個標記,一個標示學校位置,另一個標示住家或其他有意義的位置。
  4. 變更預設顏色或將預設標記圖示換成自訂圖片,即可自訂標記圖示。

提示:請參閱 onMapReady (GoogleMap googleMap) 說明文件。

回答以下問題

第 1 題

地圖載入完成並可在應用程式中使用時,系統會呼叫哪個方法?

第 2 題

您可以使用哪些 Android 元件,在應用程式中加入 Google 地圖?

  • MapViewMapFragment
  • MapFragmentMapActivity
  • MapViewMapActivity
  • 僅限 MapFragment

第 3 題

Google 地圖 Android API 提供哪些類型的地圖?

  • 一般、混合、地形、衛星和道路圖
  • 一般、混合、地形、衛星和「無」
  • 混合、地形、衛星、路線圖和「無」
  • 一般、地形、衛星、圖片地圖和「無」

第 4 題

您實作哪個介面,為搜尋點 (POI) 新增點擊功能?

  • GoogleMap.OnPoiListener
  • GoogleMap.OnPoiClickListener
  • GoogleMap.OnPoiClick
  • GoogleMap.OnPoiClicked

提交應用程式以供評分

評分者專用指南

請確認應用程式具備下列功能:

  • 應用程式啟動時,Google 地圖會正確顯示,表示 API 金鑰已順利產生。
  • Google 地圖載入後,攝影機會移至學生的住家或學校位置。在程式碼中,這個步驟應在 onMapReady (GoogleMap googleMap) 回呼方法中進行。
  • 地圖上會顯示學生的學校位置和另一個位置 (例如住家)。
  • 這兩個標記都經過自訂。舉例來說,標記使用的顏色不是預設的紅色,或是使用自訂圖示。

12. 下一個程式碼研究室

如要查看進階 Android 開發訓練課程的所有程式碼研究室,請前往進階 Android 開發程式碼研究室到達網頁