代表路徑和區域的折線和多邊形

本教學課程說明如何在 Android 應用程式中加入 Google 地圖,並使用折線和多邊形來表示地圖上的路徑和區域。

請按照教學課程,使用 Maps SDK for Android 建構 Android 應用程式。建議的開發環境為 Android Studio

取得程式碼

從 GitHub 複製或下載 Google Maps Android API 第 2 版範例存放區

設定您的開發專案

如要在 Android Studio 中建立教學課程專案,請按照下列步驟操作。

  1. 下載安裝 Android Studio。
  2. Google Play 服務套件加入 Android Studio。
  3. 如果您在閱讀本教學課程時尚未複製或下載 Google Maps Android API 第 2 版範例存放區,請先複製或下載。
  4. 匯入教學課程專案:

    • 在 Android Studio 中,選取 [File] (檔案) > [New] (新增) > [Import Project] (匯入專案)
    • 下載完成後,請前往您儲存 Google Maps Android API 第 2 版範例存放區的位置。
    • 在這個位置找到 Polygons 專案:
      PATH-TO-SAVED-REPO/android-samples/tutorials/Polygons
    • 選取專案目錄,然後按一下 [OK] (確定)。Android Studio 現在會使用 Gradle 建構工具來建立您的專案。

取得 API 金鑰並啟用必要的 API

如想完成本教學課程,您必須取得獲權使用 Maps SDK for Android 的 Google API 金鑰。

點選下方按鈕即可取得金鑰並啟用 API。

開始使用

詳情請參閱取得 API 金鑰的完整指南。

在應用程式中加入 API 金鑰

  1. 編輯專案的 gradle.properties 檔案。
  2. 將 API 金鑰貼到 GOOGLE_MAPS_API_KEY 屬性的值中。在您建構應用程式時,Gradle 會將 API 金鑰複製到應用程式的 Android 資訊清單中,如下文所述。

    GOOGLE_MAPS_API_KEY=PASTE-YOUR-API-KEY-HERE
        

建構並執行應用程式

  1. 將 Android 裝置連接到電腦。按照操作說明為 Android 裝置啟用開發人員選項,並將系統設定為偵測裝置 (您也可以使用 Android Virtual Device (AVD) Manager 來設定虛擬裝置。選擇模擬器時,請務必挑選包含 Google API 的映像檔。詳情請參閱入門指南)。
  2. 在 Android Studio 中,按一下 [Run] (執行) 選單選項 (或播放按鈕圖示), 然後按照系統提示選擇裝置。

Android Studio 會叫用 Gradle 來建構應用程式,然後在裝置或模擬器上執行應用程式。

您應該會看到地圖上的澳洲上方有兩個多邊形重疊,與本網頁中的圖片類似。

疑難排解:

  • 如果您未看到地圖,請按照上述步驟,檢查您是否已取得 API 金鑰並將其加入應用程式。在 Android Studio 查看 Android Monitor 中的記錄檔,看看是否有關於 API 金鑰的錯誤訊息。
  • 使用 Android Studio 偵錯工具查看記錄檔並為應用程式偵錯。

瞭解程式碼

本教學課程這一段將說明多邊形應用程式最重要的部分,協助您瞭解如何建構類似的應用程式。

檢查您的 Android 資訊清單

請注意應用程式 AndroidManifest.xml 檔案中的下列元素:

  • 新增 meta-data 元素,以嵌入用來編譯應用程式的 Google Play 服務版本。

    <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        
  • 新增指定 API 金鑰的 meta-data 元素。本教學課程隨附的範例會將 API 金鑰的值對應至字串google_maps_key。 在您建構應用程式時,Gradle 會將 API 金鑰從專案的 gradle.properties 檔案複製到字串值。

    <meta-data
          android:name="com.google.android.geo.API_KEY"
          android:value="@string/google_maps_key" />
        

    如要瞭解 API 金鑰如何對應至字串值,請查看應用程式的 build.gradle。其中會包含以下這一行,將 google_maps_key 字串對應至 gradle 屬性 GOOGLE_MAPS_API_KEY

    resValue "string", "google_maps_key",
                (project.findProperty("GOOGLE_MAPS_API_KEY") ?: "")
        

以下是資訊清單的完整範例:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.polygons">

        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">

            <meta-data
                android:name="com.google.android.gms.version"
                android:value="@integer/google_play_services_version" />

            <!--
                 The API key for Google Maps-based APIs.
            -->
            <meta-data
                android:name="com.google.android.geo.API_KEY"
                android:value="@string/google_maps_key" />

            <activity
                android:name="com.example.polygons.PolyActivity"
                android:label="@string/title_activity_maps">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>

    

新增地圖

使用 Maps SDK for Android 顯示地圖。

  1. 在活動的版面配置檔案 activity_maps.xml 中加入 <fragment> 元素。這個元素會將 SupportMapFragment 定義為地圖的容器並提供 GoogleMap 物件的存取權。本教學課程使用 Android 支援資料庫版本的地圖片段,確保與舊版 Android 架構能回溯相容。

        <fragment xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context="com.example.polygons.PolyActivity" />
    
        
  2. 在活動的 onCreate() 方法中,將版面配置檔案設為內容檢視畫面。呼叫 FragmentManager.findFragmentById() 以取得地圖片段的處理常式,然後使用 getMapAsync() 註冊地圖回呼:

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // Retrieve the content view that renders the map.
            setContentView(R.layout.activity_maps);
    
            // Get the SupportMapFragment and request notification when the map is ready to be used.
            SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(map);
            mapFragment.getMapAsync(this);
        }
        
  3. 導入 OnMapReadyCallback 介面並覆寫 onMapReady() 方法。當 GoogleMap 物件可用時,API 會叫用這個回呼,因此您可以在地圖中加入物件,並進一步為應用程式自訂物件:

    public class PolyActivity extends AppCompatActivity
                implements
                        OnMapReadyCallback,
                        GoogleMap.OnPolylineClickListener,
                        GoogleMap.OnPolygonClickListener {
    
            // More code goes here, including the onCreate() method described above.
    
            @Override
            public void onMapReady(GoogleMap googleMap) {
    
                // Add polylines and polygons to the map. This section shows just
                // a single polyline. Read the rest of the tutorial to learn more.
                Polyline polyline1 = googleMap.addPolyline(new PolylineOptions()
                        .clickable(true)
                        .add(
                                new LatLng(-35.016, 143.321),
                                new LatLng(-34.747, 145.592),
                                new LatLng(-34.364, 147.891),
                                new LatLng(-33.501, 150.217),
                                new LatLng(-32.306, 149.248),
                                new LatLng(-32.491, 147.309)));
    
                // Position the map's camera near Alice Springs in the center of Australia,
                // and set the zoom factor so most of Australia shows on the screen.
                googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(-23.684, 133.903), 4));
    
                // Set listeners for click events.
                googleMap.setOnPolylineClickListener(this);
                googleMap.setOnPolygonClickListener(this);
            }
        }
        

新增折線以在地圖上繪製線條

Polyline 是一系列連接的線段。折線可用於表示地圖上的路線、路徑或不同位置之間的其他交通路線。

  1. 建立 PolylineOptions 物件並新增路徑點。 每個路徑點都代表地圖上的一個位置,您可以使用包含緯度和經度值的 LatLng 物件定義該位置。下方的程式碼範例會建立一個含有 6 個路徑點的折線。

  2. 呼叫 GoogleMap.addPolyline() 即可將折線加入地圖。

    Polyline polyline1 = googleMap.addPolyline(new PolylineOptions()
                .clickable(true)
                .add(
                        new LatLng(-35.016, 143.321),
                        new LatLng(-34.747, 145.592),
                        new LatLng(-34.364, 147.891),
                        new LatLng(-33.501, 150.217),
                        new LatLng(-32.306, 149.248),
                        new LatLng(-32.491, 147.309)));
        

如果您要處理折線上的點擊事件,請將折線的 clickable 選項設為 true。本教學課程稍後將進一步說明事件處理方式。

使用折線儲存任意資料

您可以使用折線和其他幾何物件來儲存任意資料物件。

  1. 呼叫 Polyline.setTag() 即可使用折線儲存資料物件。以下程式碼會定義指定折線類型的任意標記 (A)。

    Polyline polyline1 = googleMap.addPolyline(new PolylineOptions()
                .clickable(true)
                .add(
                        new LatLng(-35.016, 143.321),
                        new LatLng(-34.747, 145.592),
                        new LatLng(-34.364, 147.891),
                        new LatLng(-33.501, 150.217),
                        new LatLng(-32.306, 149.248),
                        new LatLng(-32.491, 147.309)));
        // Store a data object with the polyline, used here to indicate an arbitrary type.
        polyline1.setTag("A");
        
  2. 使用 Polyline.getTag() 可擷取資料,如下一節所示。

在折線中加入自訂樣式

您可以在 PolylineOptions 物件中指定各種樣式屬性。樣式選項包括筆劃顏色、筆劃寬度、筆劃模式、轉折類型,以及筆劃開始及結束的端點形狀。如果您未指定特定屬性,API 就會使用該屬性的預設值。

下方程式碼會在線條末端套用圓形端點形狀,並根據折線的「類型」套用不同的開始端點形狀;類型是指儲存在折線資料物件中的任意屬性。範例中也指定了筆劃寬度、筆劃顏色和轉折類型:

    private static final int COLOR_BLACK_ARGB = 0xff000000;
    private static final int POLYLINE_STROKE_WIDTH_PX = 12;

    private void stylePolyline(Polyline polyline) {
        String type = "";
        // Get the data object stored with the polyline.
        if (polyline.getTag() != null) {
            type = polyline.getTag().toString();
        }

        switch (type) {
            // If no type is given, allow the API to use the default.
            case "A":
                // Use a custom bitmap as the cap at the start of the line.
                polyline.setStartCap(
                        new CustomCap(
                                BitmapDescriptorFactory.fromResource(R.drawable.ic_arrow), 10));
                break;
            case "B":
                // Use a round cap at the start of the line.
                polyline.setStartCap(new RoundCap());
                break;
        }

        polyline.setEndCap(new RoundCap());
        polyline.setWidth(POLYLINE_STROKE_WIDTH_PX);
        polyline.setColor(COLOR_BLACK_ARGB);
        polyline.setJointType(JointType.ROUND);
    }
    

上述程式碼會指定 A 類型折線開始端點形狀的自訂點陣圖,並將參考筆劃寬度指定為 10 像素。API 會根據參考筆劃寬度調整點陣圖比例。指定參考筆劃寬度時,請提供您在設計點陣圖圖片時使用的寬度 (以圖片的原始尺寸為準)。提示:在圖片編輯器中開啟點陣圖圖片並縮放至 100%,然後繪製相對於圖片的特定線條筆劃寬度。

進一步瞭解線條端點形狀自訂形狀的其他選項。

處理折線上的點擊事件

  1. 呼叫 Polyline.setClickable() 即可將折線設為可點擊 (折線根據預設為不可點擊,使用者輕觸折線時,您的應用程式也不會收到通知)。

  2. 導入 OnPolylineClickListener 介面並呼叫 GoogleMap.setOnPolylineClickListener(),即可在地圖上設定事件監聽器:

    public class PolyActivity extends AppCompatActivity
                implements
                        OnMapReadyCallback,
                        GoogleMap.OnPolylineClickListener,
                        GoogleMap.OnPolygonClickListener {
    
            @Override
            public void onMapReady(GoogleMap googleMap) {
                // Add a polyline to the map.
                Polyline polyline1 = googleMap.addPolyline((new PolylineOptions())
                        .clickable(true)
                        .add(new LatLng(-35.016, 143.321),
                                new LatLng(-34.747, 145.592),
                                new LatLng(-34.364, 147.891),
                                new LatLng(-33.501, 150.217),
                                new LatLng(-32.306, 149.248),
                                new LatLng(-32.491, 147.309)));
    
                // Set listeners for click events.
                googleMap.setOnPolylineClickListener(this);
                googleMap.setOnPolygonClickListener(this);
            }
        }
        
  3. 覆寫 onPolylineClick() 回呼方法。以下範例顯示使用者點擊折線時,線條筆劃模式在實線和虛線之間替換的方式:

        private static final PatternItem DOT = new Dot();
        private static final PatternItem GAP = new Gap(PATTERN_GAP_LENGTH_PX);
        //
        // Create a stroke pattern of a gap followed by a dot.
        private static final List<PatternItem> PATTERN_POLYLINE_DOTTED = Arrays.asList(GAP, DOT);
    
        @Override
        public void onPolylineClick(Polyline polyline) {
            // Flip from solid stroke to dotted stroke pattern.
            if ((polyline.getPattern() == null) || (!polyline.getPattern().contains(DOT))) {
                polyline.setPattern(PATTERN_POLYLINE_DOTTED);
            } else {
                // The default pattern is a solid stroke.
                polyline.setPattern(null);
            }
    
            Toast.makeText(this, "Route type " + polyline.getTag().toString(),
                    Toast.LENGTH_SHORT).show();
        }
        

新增多邊形來代表地圖上的區域

Polygon 是一個由一系列座標依序組成的形狀 (與 Polyline 類似)。不同之處在於,多邊形定義了內部可填充的封閉區域,折線則是開放式的。

  1. 建立 PolygonOptions 物件並新增路徑點。 每個路徑點都代表地圖上的一個位置,您可以使用包含緯度和經度值的 LatLng 物件定義該位置。下方的程式碼範例會建立一個含有 4 個路徑點的多邊形。

  2. 呼叫 Polygon.setClickable() 即可將多邊形設為可點擊 (多邊形根據預設為不可點擊,使用者輕觸多邊形時,您的應用程式也不會收到通知)。處理多邊形點擊事件與處理折線上的事件類似,如本教學課程前文所述。

  3. 呼叫 GoogleMap.addPolygon() 可將多邊形加入地圖。

  4. 呼叫 Polygon.setTag() 可儲存包含多邊形的資料物件。以下程式碼會定義多邊形的任意類型 (alpha)。

    Polygon polygon1 = googleMap.addPolygon(new PolygonOptions()
                .clickable(true)
                .add(
                        new LatLng(-27.457, 153.040),
                        new LatLng(-33.852, 151.211),
                        new LatLng(-37.813, 144.962),
                        new LatLng(-34.928, 138.599)));
        // Store a data object with the polygon, used here to indicate an arbitrary type.
        polygon1.setTag("alpha");
        

在多邊形中加入自訂樣式

您可以在 PolygonOptions 物件中指定多個樣式屬性。樣式選項包括筆劃顏色、筆劃寬度、筆劃模式、筆劃轉折類型和填滿顏色。如果您未指定特定屬性,API 就會使用該屬性的預設值。

以下程式碼會根據多邊形的「類型」套用特定顏色和筆劃模式;類型是指儲存在多邊形資料物件中的任意屬性。

    private static final int COLOR_BLACK_ARGB = 0xff000000;
    private static final int COLOR_WHITE_ARGB = 0xffffffff;
    private static final int COLOR_GREEN_ARGB = 0xff388E3C;
    private static final int COLOR_PURPLE_ARGB = 0xff81C784;
    private static final int COLOR_ORANGE_ARGB = 0xffF57F17;
    private static final int COLOR_BLUE_ARGB = 0xffF9A825;

    private static final int POLYGON_STROKE_WIDTH_PX = 8;
    private static final int PATTERN_DASH_LENGTH_PX = 20;
    private static final int PATTERN_GAP_LENGTH_PX = 20;
    private static final PatternItem DOT = new Dot();
    private static final PatternItem DASH = new Dash(PATTERN_DASH_LENGTH_PX);
    private static final PatternItem GAP = new Gap(PATTERN_GAP_LENGTH_PX);

    // Create a stroke pattern of a gap followed by a dash.
    private static final List<PatternItem> PATTERN_POLYGON_ALPHA = Arrays.asList(GAP, DASH);

    // Create a stroke pattern of a dot followed by a gap, a dash, and another gap.
    private static final List<PatternItem> PATTERN_POLYGON_BETA =
            Arrays.asList(DOT, GAP, DASH, GAP);

    private void stylePolygon(Polygon polygon) {
        String type = "";
        // Get the data object stored with the polygon.
        if (polygon.getTag() != null) {
            type = polygon.getTag().toString();
        }

        List<PatternItem> pattern = null;
        int strokeColor = COLOR_BLACK_ARGB;
        int fillColor = COLOR_WHITE_ARGB;

        switch (type) {
            // If no type is given, allow the API to use the default.
            case "alpha":
                // Apply a stroke pattern to render a dashed line, and define colors.
                pattern = PATTERN_POLYGON_ALPHA;
                strokeColor = COLOR_GREEN_ARGB;
                fillColor = COLOR_PURPLE_ARGB;
                break;
            case "beta":
                // Apply a stroke pattern to render a line of dots and dashes, and define colors.
                pattern = PATTERN_POLYGON_BETA;
                strokeColor = COLOR_ORANGE_ARGB;
                fillColor = COLOR_BLUE_ARGB;
                break;
        }

        polygon.setStrokePattern(pattern);
        polygon.setStrokeWidth(POLYGON_STROKE_WIDTH_PX);
        polygon.setStrokeColor(strokeColor);
        polygon.setFillColor(fillColor);
    }
    

進一步瞭解筆劃模式自訂形狀的其他選項。

其他訣竅

瞭解圓形物件。圓形與多邊形類似,但形狀屬性為圓形。