Android 地圖與定位 (Maps and Positioning)(2)

Maps and Positioning

在應用程式中使用 GoogleMap 類別來建立地圖物件,地圖物件可以在 MapFragmentMapView 中顯示。

GoogleMap 幫我們做了哪些事:
  • 連結到 Google Maps service。
  • 下載圖資。
  • 在螢幕上顯示地圖。
  • 顯示控制按鈕,例如平移及縮放。
  • 執行平移及縮放手勢。

使用地圖

MapFragment

MapFragment 是一個放置地圖的容器,是 Fragment 的子類別。Google Maps Android API 要求 API level 12(Android 3.1) 或更高的 API 來支援 MapFragment 物件。假如要使用較舊的 API ,可以透過 SupportMapFragment 類別來達到同樣的功能,請參考 Support Library

MapView

MapView 一樣是一個放置地圖的容器。使用 MapView 會有和 Activity 相對應的生命週期方法,onCreate()、onDestroy()、onResume()、onPause()。

取得地圖物件

GoogleMap mMap = ((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap();

設定地圖類型

地圖共有 5 種類型:
  • Normal:典型的地圖。
  • Hybrid:混合衛星照片及道路地圖。
  • Satellite:衛星照片。
  • Terrain:地形圖。
  • None:什麼都沒有。
使用 setMapType 即可改變類型,如下:
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);

初始化地圖狀態

可以設定地圖狀態有:
  • 攝影機的位罝,包含 location(位置), zoom(縮放), bearing(軸承) 及 tilt(傾斜),詳細資料請參考如何更改地圖視點
  • 地圖的類型。
  • 是否顯示 zoom 按鈕及是否在螢幕上顯示羅盤。
  • 使用者可以使用哪些手勢來操作地圖。
使用 xml 來設定,如下:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:map="http://schemas.android.com/apk/res-auto"
  android:id="@+id/map"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  class="com.google.android.gms.maps.MapFragment"
  map:cameraBearing="45"
  map:cameraTargetLat="25.033611"
  map:cameraTargetLng="121.565000"
  map:cameraTilt="0"
  map:cameraZoom="13"
  map:mapType="normal"
  map:uiCompass="true"
  map:uiRotateGestures="true"
  map:uiScrollGestures="true"
  map:uiTiltGestures="true"
  map:uiZoomControls="false"
  map:uiZoomGestures="true"/>
這裡的地裡位置使用 MyGeoPosition 反查台北101後取後得 GPX 資料中的經緯度輸入 cameraTargetLat 及 cameraTargetLng 這兩個屬性。

若是使用程式碼來加入 MapFragment 或 MapView ,則可以用 GoogleMapOptions 類別來設定,如下:
GoogleMapOptions options = new GoogleMapOptions();
options.compassEnabled(false);
在 MapFragment 中使用 MapFragment.newInstance(GoogleMapOptions options)這個方法。在 MapView 中使用 MapView(Context, GoogleMapOptions)。

標記(Markers)

標記(Marker)類別可用來指出地圖上的某一個地點,預設的標記和 Google Map 中使用的一樣,你也可以自訂標記的顏色或使用其他圖示來呈現。

標記是描繪在裝置的螢幕而不是地圖的表面,所以旋轉、傾斜及縮放等的動作並不需要去對標記做相對應的改變。標記被設計成可以和使用者互動,預設能接收 click 事件,若將 draggable 屬性設成 true,則可以讓使用者在長按標記後移動它。
新增標記
使用 MarkerOptions 類別來建立標記選項,使用 LatLng 類別來建立經緯度,所以程式碼如下:
MarkerOptions markerOpt = new MarkerOptions();
markerOpt.position(new LatLng(25.033611, 121.565000));
markerOpt.title("台北101");
markerOpt.draggable(true);

mMap.addMarker(markerOpt);
我將標記設在台北101的經緯度,在標記上點一下會出現 "台北101" 的標題,長按可移動標記。
自訂標記
可自訂的標記屬性:
  • Position(必要):使用 LatLng 類別來設定位置,這是唯一必要設定的屬性。
  • Title:使用者點一下標記時顯示的標題文字。
  • Snippet:額外的文字,顯示在標題文字下方。
  • Draggable:是否可以讓使用者移動標記,true 可移動;false 則否。
  • Visible:是否顯示標記,true 顯示;false隱藏。
  • Anchor:圖片上的一個點,用來定位到經緯度座標,預設為圖片的中間下緣。值為左上角(0.0, 0.0)到右下角(1.0, 1.0)。
  • Icon:圖示,被放置在原標記的相同位置,只有第一次建立標記時可以使用圖示,之後就不能任意更換圖示。
範例程式碼:
//Marker1
MarkerOptions markerOpt = new MarkerOptions();
markerOpt.position(new LatLng(25.033611, 121.565000));
markerOpt.title("台北101");
markerOpt.snippet("於1999年動工,2004年12月31日完工啟用,樓高509.2公尺。");
markerOpt.draggable(false);
markerOpt.visible(true);
markerOpt.anchor(0.5f, 0.5f);//設為圖片中心
markerOpt.icon(BitmapDescriptorFactory.fromResource(android.R.drawable.ic_menu_mylocation));

mMap.addMarker(markerOpt);

//Marker2
MarkerOptions markerOpt2 = new MarkerOptions();
markerOpt2.position(new LatLng(25.047924, 121.517081));
markerOpt2.title("台北火車站");

mMap.addMarker(markerOpt2);
第一個標記一樣是台北101,圖示我隨意挑了一個 Android 內建的圖示來使用,錨點則設為該圖示的正中心;另外新增第二個標記為台北火車站,可以比較兩者的差異。

此外,你也可以改變預設圖示的顏色,程式碼如下:
//Marker3
MarkerOptions markerOpt3 = new MarkerOptions();
markerOpt3.position(new LatLng(25.042902, 121.515030));
markerOpt3.title("國立台灣博物館");
markerOpt3.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));

mMap.addMarker(markerOpt3);
使用 BitmapDescriptorFactory.defaultMarker(float hue) 方法可以去選擇幾種內定的顏色。
標記的資訊視窗
資訊視窗即是前面所設定的 title 屬性所顯示的資料,當使用者點選時才會顯示,並且一次只會顯示一個,當使用者點選另一個標記時,前一個標記所顯示的資訊視窗就會消失。可以在程式中呼叫 showInfoWindow() 方法來顯示資訊視窗,然後呼叫 hideInfoWindow() 方法來隱藏。

資訊視窗可以自訂樣子,必須實作 GoogleMap.InfoWindowAdapter 介面,然後呼叫 setInfoWindowAdapter (GoogleMap.InfoWindowAdapter adapter) 方法。

InfoWindowAdapter 介面只有兩個方法,getInfoWindow (Marker marker) 及 getInfoContents (Marker marker),API 會先呼叫 getInfoWindow 這個方法,如果回傳是 null 就會呼叫 getInfoContents 方法,如果還是 null ,就會使用預設的資訊視窗。

getInfoWindow 方法可以讓你自訂整個資訊視窗的 view 也就是視窗的外觀及背景等,getInfoContents 方法則只有自訂內容,視窗的外觀則是用預設的。

下圖是官方的範例圖片:左邊是預設,中間是自訂內容,右邊是自訂視窗。 (圖片來源:https://developers.google.com/maps/documentation/android/marker?hl=zh-TW)
事件
事件種類:

在地圖上畫圖

使用 Polyline 可以將地圖上的點依序連接畫出一條條的線段;使用 Polygon 可以依地圖上的點畫出一個封閉圖形。

在地圖上的點座標是由經緯度表示,所以 Polyline 基本上就由一組經緯度座標點所組成,經緯度座標使用 LatLng 類別來建立。

Polyline 需使用 PolylineOptions 類別來建立,像是加入座標點、線條顏色等,之後再使用 GoogleMap.addPolyLine 把線段加入地圖。

以下範例程式碼是從台北101畫一條路徑到台北火車站,如下:
private void drawPolyline(){
    PolylineOptions polylineOpt = new PolylineOptions();
    polylineOpt.add(new LatLng(25.033611, 121.565000));
    polylineOpt.add(new LatLng(25.032728, 121.565137));
    polylineOpt.add(new LatLng(25.033739, 121.527886));
    polylineOpt.add(new LatLng(25.038716, 121.517758));
    polylineOpt.add(new LatLng(25.045656, 121.519636));
    polylineOpt.add(new LatLng(25.046200, 121.517533));

    polylineOpt.color(Color.BLUE);

    Polyline polyline = mMap.addPolyline(polylineOpt);
    polyline.setWidth(10);
}
結果如下: 線段為藍色 10 px。

有些屬性可以在 PolylineOptions 中設定,但也可以在加入地圖後取得的 Polyline 中設定。

Polygon 實做方法基本上差不多,只是多了可以對封閉圖形填色的功能。

改變視點

透過移動攝影機的方式來改變看地圖的視點,改變攝影機不會對你加入的標記、圖層或自訂的圖片造成影響。

攝影機的屬性有:
  • Target (Location)
  • Zoom
  • Bearing (orientation)
  • Tilt (viewing angle)

Target (Location)

以經緯度座標來指定攝影機在地圖上的位置。

Zoom

縮放的層級 (level) 決定了地圖的縮放比例 (scale)。最小的層級 level 0 可以看到整個世界(寬大約是256dp),最大的層級則可以看到地圖上最細節的資料,每升一級,地圖以寬為準的縮放比例就會放大一倍(約256 * 2N dp)。縮放層級(level)不一定要是整數。可用的縮放層級範圍取決於數個因素,包含位置、地圖類型及螢幕尺寸。

Bearing (orientation)

以地圖的某個點畫一個垂直線,從北方順時針測量的角度。例如使用GPS導航裝置時,會以地圖朝北的方向來看地圖。API 允許開發者改變這個地圖的指向,如果把角度設為90度,那地圖就會逆時針轉向(指向是順時針,所以看起來地圖是逆時針),東邊就會轉向地圖的正上方。

Tilt (viewing angle)

攝影機的位置是在地圖正中央的上方,以一個弧度的方式延伸到地平面(類似我們在地球上看太陽從東水平線出現,中午在頭頂,在西水平線消失)。看圖比較快: (圖片來源:https://developers.google.com/maps/documentation/android/views?hl=zh-TW)

位置1為攝影機的位置,位置2為地圖的位置,所以我們所看地圖的方式,就是從正上方往下看地圖,透過移動攝影機(位置1)在弧線上的位置,就會看到有傾斜角的地圖(像是從側面看地圖),這個範圍從最上方的0度到最低的90度。

移動攝影機

這裡是指改變攝影機的位置來決定看到地圖上的哪部份的資料,而不是移動地圖。要改變攝影機的位置,你必須指定攝影機要移動到哪裡,使用 CameraUpdate 。Maps API 允許開發者透過 CameraUpdateFactory 建立多個不同類型的 CameraUpdate。

選項有:
  • 改變縮放層級 (zoom level)
  • 改變攝影機位置
  • 設定邊界
  • 平移或捲動
範例程式碼如下:
public void moveOnClick(View v){
    //move camera
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(KENTING, 15));
}

public void zoomInOnClick(View v){
    //zoom in
    mMap.animateCamera(CameraUpdateFactory.zoomIn());
}

public void zoomToOnClick(View v){
    //zoom to level 10, animating with a duration of 3 seconds
    mMap.animateCamera(CameraUpdateFactory.zoomTo(10), 3000, null);
}

public void animToOnClick(View v){
    //將攝影機移動到日月潭
    CameraPosition cameraPosition = new CameraPosition.Builder()
    .target(ZINTUN)              // Sets the center of the map to ZINTUN
    .zoom(13)                   // Sets the zoom
    .bearing(90)                // Sets the orientation of the camera to east
    .tilt(30)                   // Sets the tilt of the camera to 30 degrees
    .build();                   // Creates a CameraPosition from the builder
    mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
在這篇文章中程式碼用到的地點的經緯度如下:
//台北101
final LatLng TAIPEI101 = new LatLng(25.033611, 121.565000);
//台北火車站
final LatLng TAIPEI_TRAIN_STATION = new LatLng(25.047924, 121.517081);
//國立台灣博物館
final LatLng NATIONAL_TAIWAN_MUSEUM = new LatLng(25.042902, 121.515030);

//墾丁
final LatLng KENTING = new LatLng(21.946567, 120.798713);
//日月潭
final LatLng ZINTUN = new LatLng(23.851676, 120.902008);
全部由 MyGeoPosition.com 反查。
範例程式碼下載:GoogleMapDemo.zip

參考資料:

本文網址:http://blog.tonycube.com/2013/01/androidmaps-and-positioning2.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

97 則留言

  1. 您好,我想請問一下如何抓取手機裝置當下位置的經緯度??
    我想實作出一開啟google map,中心點即是我目前的位置
    謝謝您!!

    回覆刪除
    回覆
    1. 抱歉我補充一下,我是使用SupportMapFragment來呈現地圖

      刪除
    2. 使用LocationManager(http://developer.android.com/reference/android/location/LocationManager.html) 的 getLastKnownLocation()方法會取得最後一次GPS紀錄的位置(可能沒有值或資料是舊的,取決於GPS最後何時更新),

      傳回的Location(http://developer.android.com/reference/android/location/Location.html)物件的 getLongitude()方法可取得經度,getLatitude()則是取緯度。

      刪除
  2. 你好我想請問一下
    我跟樓上一樣也正在做一個 GOOGLE MAP GPS定位目前位置
    (但我跟版主一樣是使用MapFragment 呈現地圖)
    我也已經用getLongitude()和getLatitude()取得目前的經緯度
    但是在GPS 的public onLocationChanged()當中
    我有印出getLongitude()和getLatitude()的值
    也成功使用DDMS來模擬GPS的經緯度
    但我想用MarkerOption來標記出來目前的位置
    不知道怎麼用 可否教教我 感謝您!! =)

    回覆刪除
    回覆
    1. 像範例一樣
      MarkerOptions markerOpt2 = new MarkerOptions();
      markerOpt2.position(new LatLng(緯度, 經度));
      markerOpt2.title("目前的位置");

      mMap.addMarker(markerOpt2);

      這樣不會出現標記嗎?

      刪除
    2. 摁摁 有出現標記了
      只是想在請問一下
      我標記上面如果想使用自己的圖片的話要如何使用

      刪除
    3. 把 Marker 的 icon 屬性換成你的圖片試試看

      可以參考: http://stackoverflow.com/questions/7823428/android-how-make-custom-viewlayout-for-marker-on-google-maps

      刪除
    4. 不好意思 可請問一下
      如果用自己的icon
      想用官網提供的 fromFile
      .icon(BitmapDescriptorFactory.fromFile("String path"));
      路徑該如何設置?

      刪除
    5. http://developer.android.com/reference/com/google/android/gms/maps/model/BitmapDescriptorFactory.html#fromFile(java.lang.String)

      看說明這個檔案會是放在 internal storage,也就是 App 裡面的目錄,只要輸入檔名即可(應該啦),但這裡儲存的圖片應該會是由 App 存入的,例如App去網路下載下來儲存的,而不是在開發時放入的資源檔(Resource)或Asset檔。

      如果你是把圖檔放在 res/drawable 之下,應該改用 fromResource(R.id.img_name) 才對。那個 img_name 是你的圖檔名。這樣不知道有沒有幫到你的忙~~

      刪除
    6. 好的 我試試看 謝謝你噢 =)

      刪除
    7. 我看我的 res/drawable 之下 有drawable-hdpi、drawable-ldpi、drawable-mdpi、drawable-xhdpi 這四個資料夾
      所以我每個都放入我要的PNG圖檔(檔名為img_123)
      options.icon(BitmapDescriptorFactory.fromResource(R.id.img_123.png));
      程式碼很像還是有錯 0.0

      刪除
    8. 喔喔!!我好像打錯了,是 "R.drawable.img_name" 才對,
      你的圖檔名若為 img_123.png, 要寫成 "R.drawable.img_123" 才對,
      副檔名不要加。

      刪除
    9. 作者已經移除這則留言。

      刪除
    10. 作者已經移除這則留言。

      刪除
    11. 可以請問
      如何用getLongitude()和getLatitude()取得目前的經緯度
      在GPS 的public onLocationChanged()當中又印出getLongitude()和getLatitude()的值嗎?
      程式碼可否參考>< 感恩~~

      刪除
  3. 不好意思我想請問一下
    用MarkerOptions需要import什麼嗎??

    MarkerOptions markerOpt = new MarkerOptions();
    markerOpt.position(new LatLng(25.033611, 121.565000));
    markerOpt.title("台北101");
    markerOpt.draggable(true);
    mMap.addMarker(markerOpt);

    我擷取這段不能用耶
    可以麻煩您教教我嗎??謝謝!!感激不盡!!

    回覆刪除
    回覆
    1. 不能用是指什麼?
      這範例只能在手機上執行喔!!

      刪除
    2. 樓上的Wade你好,應該是要import下面這個
      import com.google.android.gms.maps.model.MarkerOptions;
      我是有在模擬器上跑出來
      只是模擬器要先安裝google play的和幾個相關的apk檔
      但如果嫌麻煩 用實機跑比較快啦

      刪除
  4. 抱歉沒注意到版本問題
    我用的是Android2.1 和 Google API level 8
    所以是要用更高的版本才不會有錯囉??

    回覆刪除
    回覆
    1. 在”地圖與定位(Maps and Positioning)(1)”這篇中我就有提醒囉
      『重要!Google Play Services SDK 只支援 Android 2.2 之後的系統。』

      刪除
  5. 我想要請問一下 有辦法從抓資料庫內的經緯度和地址名稱下來標記嗎

    回覆刪除
  6. 版主可以分享一個GPS的CODE嗎?

    回覆刪除
    回覆
    1. 本來規劃在第3篇的,最近太忙,要在等等 :(

      刪除
  7. 那可以問大大 大概要在什麼地方+東西呢?

    回覆刪除
    回覆
    1. 請Google幫忙吧~~
      關鍵字 LocationManager :取得GPS
      LocationListener :可以偵聽位置的改變

      刪除
    2. 您好 我做出gps了 我每定位一個點標記一次 那要怎麼將上次的清除呢?

      刪除
    3. 應該是去改它的position吧,而不是每定位一次就產生一個標記,試試看把新的座標指定給原本的標記

      刪除
  8. 版主 請教一下
    我原本加標記都沒問題
    但是只要用icon(BitmapDescriptorFactory.fromResource(R.drawable.xxx));
    加入圖示,一執行就會立即中止說,我想問一下這大概會是哪邊出問題?

    回覆刪除
    回覆
    1. 找到解答了 = =
      http://android-question.blogspot.tw/2009/07/ibitmapdescriptorfactory-is-not.html
      不過我想問這是幹嘛的 為什麼我沒加就會直接中止...

      刪除
    2. 版主 我有新問題想問 我如何讓user自行新增圖檔呢?
      我想要做那種會有瀏覽,然後自己選圖這種的? 對我這個Android新手來講難度太高了...

      刪除
    3. ..一直回覆有點不好意思 不過好像看到不錯的辦法? 不知可不可行
      一開始是用預設圖示 使用者點擊後可以換圖示 會跳到另個頁面選擇檔案 然後回傳路徑 把路徑圖回mark 然後換圖示的方法用這篇https://groups.google.com/forum/?fromgroups=#!topic/google-maps-api/kvVq7vlF9Do

      刪除
    4. 自己找解答的行為是好的 :)

      BitmapDescriptorFactory 錯誤在於 GoogleMap,GoogleMap 在建立後必須使用 getMap() 並檢查是否不為 null 才能用,另外一個相同的方法就是 MapsInitializer.initialize(Context),它會確保丟回一個可用的物件。

      換圖示的作法,你可以先看一下官方說明:https://developers.google.com/maps/documentation/android/marker#customize_a_marker

      Icon
      A bitmap that's displayed in place of the default marker image. You can't change the icon once you've created the marker.

      也就是說,icon 一建立就不能被改變,如果要達到你的要求,就必須"刪除既有的,建立新的取代"來做。

      刪除
    5. 版主 在請教一下~
      我想達到一個頁面是聊天室 一個頁面是Google map即時定位
      有辦法在進入這程式時就讓這兩件事同時執行嗎?
      因為手機螢幕小,所以不想放在同頁面 = =
      還是有其他方法可以達到相同效果.

      刪除
    6. "Google map即時定位"其實做了兩件事,一件是GPS定位,一件是顯示位置在 map 上,所以應該是在聊天頁面的背景做GPS定位,但並沒有顯示任何畫面,當使用者切換到地圖的頁面時,該頁面可以立即取得GPS定位的資料,顯示在 map 上。

      但一直抓GPS定位的資料其實很耗電,所以我覺得應該是切換到地圖頁面時在去抓,或是進入聊天頁面時,只抓一次目前所在位置(或每隔一段時間),存下來,在使用者切換到地圖時就可立即使用,這時再定位一次去抓位置來更新。

      刪除
    7. 因為我想作的是多人即時定位通訊 如果要達到你說的切到到地圖頁面上再取讀定位資料 這樣要把資料存在資料庫嗎?

      刪除
    8. 剛想一下 好像用fragment可以達到我的需求的樣子 = =

      刪除
    9. fragment可以。

      "多人即時定位通訊"!?那不就和LINE什麼的很像?

      要多人就要架伺服器了吧。抓GPS定位的機制可以如我前面所說,每隔一段時間抓,但因為要多人同步位置,所以要同時上傳位置資料到伺服器,然後下載其他人的位置資料回來。(人多的時候,伺服器的負載會是個大課題)

      感覺你的題目有點大@@"

      刪除
    10. 恩.. 伺服器方面是還好,畢竟只是嘗試看看,最多測試幾個人,我比較困惱android方面~
      因為第一次碰,都不知道有什是我可以用的..

      刪除
  9. 版主你好,想請教一下,有辦法讓Camera在設定target的時候,不要設定到螢幕正中央,而是像下圖中的螢幕中間下方嗎,我瀏覽過整個MAP camera的API好像沒有解法,
    圖:
    http://www.google.com/mobile/images/navigation/screenshots/full/nav-gallery-18.jpg

    回覆刪除
    回覆
    1. 手滑太早發布,希望能聽聽您的意見,謝謝。

      刪除
    2. 找到一個解法,http://stackoverflow.com/questions/16764002/how-to-center-the-camera-so-that-marker-is-at-the-bottom-of-screen-google-map

      和我原本想的差不多,只是不知道可不可行,既然有人也這麼做,所以應該是可以試試看。

      因為 Camera 永遠對準中心,也如你所說,API中沒有其他可用的方法可以調整,所以不能對 Camera 動手,而是應該去調整地圖的中心點。例如原本的點A在正中央,我們就在它的上面找一個新的點B,點B會在點A及地圖上緣的一半處(或自己決定的距離),接著計算出點B的座標,讓 Camera 去對準點B,所以看起來點A就會靠近地圖下緣了。

      你試試看吧~~

      刪除
  10. 作者已經移除這則留言。

    回覆刪除
  11. 版主你好 請問一下點擊之後的資訊框
    如何資訊框載入圖片?

    回覆刪除
    回覆
    1. 這個我沒實際做過,所以也不知道怎麼做。

      刪除
  12. 版主您好,我最近開始在碰googlemap這一塊,有些問題想問
    1.mapview在現在還可以使用嗎? 我使用上一直遇到驗證問題
    去查mapview好像只能吃V1 Key,現在V1KEY已經不給申請了
    所以像傳統的自己做overlay加上去的方式是不是已經也等同無效了?

    2.我現在是使用mapfragment的方式去乘載google map進來使用
    請問有方法在上面新增自訂的圖片嗎?我想在上面固定顯示一個圖片作指引
    不過查最近接近的好像只有自訂Marker,但是Marker會跟GPS綁再一起無法固定在XY座標上,請問有建議的方法嗎? 謝謝

    回覆刪除
    回覆
    1. 其實我是從V2才開始研究的,所以V1我並不熟,即然Google自己都說不建議使用V1了,那最好還是轉移到V2比較好。

      Marker是依經緯度座標設定位置,所以一定是固定在地圖上隨地圖移動,你如果要做一個不管地圖怎麼移動,都固定在某處,那你可以在 map 上疊一個 ImageView ,你可以看 http://blog.tonycube.com/2013/06/androidmaps-and-positioning3.html 這篇,我就是在上面疊一個文字框,不管地圖怎麼動,它都固定在上方,不知道這是不是你要的。

      刪除
    2. 版主您好:

      我想請問一下,如果是使用imageview的方式,有辦法實現出縮放的功能嗎??

      請問一下,有辦法呈現出覆蓋在googlemap的某個區域,可以隨著googlemap縮放嗎??

      因為找了很多都是使用mapview,自己做過也會出現類似上面的問題,因此想請問一下版主。

      感謝

      刪除
    3. 試試看 Tile Overlay
      https://developers.google.com/maps/documentation/android/tileoverlay

      用 ImageView 的話,基本上它和 MapView 是屬於兩個不同的元件,硬做的話效能也不好。

      Tile Overlay 只是在 MapView 本身加上一個圖層,所以你其實還是在控制 MapView。

      刪除
  13. 請問一下,LatLng可以單獨取出latitude或著longitude嗎?

    回覆刪除
    回覆
    1. 查看 API 文件
      http://developer.android.com/reference/com/google/android/gms/maps/model/LatLng.html

      它有兩個 Fields
      分別是
      public final double latitude
      public final double longitude
      所以你可以對你的 LatLng 物件直接 .latitude 或 .longitude 來單獨取得。

      刪除
  14. 請問一下,如果使用標記,可以讓他自動顯示訊息並且一次多個標記顯示訊息嗎?

    也就是說可以不用去點擊他就直接顯示訊息

    剛接觸Android軟體開發,所以不太清楚就麻煩大大回答了

    回覆刪除
    回覆
    1. 應該是不行,只能去點它才顯示,而且一次只能顯示一個,這是官方文件的說法,我沒實際去研究,你可以自己試試看。

      刪除
  15. 请问一下,我怎么按标记(多个标记位置不同都显示在地图上)的边界 来缩放地图的大小
    比如我想显示周围5km内的标记,怎么在地图上全部显示出来

    回覆刪除
    回覆
    1. 你可以試試看 LatLngBounds
      https://developers.google.com/maps/documentation/android/views?hl=zh-TW#setting_boundaries

      經緯度要換算成距離可以參考這個 http://www.movable-type.co.uk/scripts/latlong.html

      刪除
  16. 板大 請問一下
    我從資料庫抓取經緯度下來
    要標記在地圖上

    那麼如何做到彈性一點的標記
    也就是說 上述提到的都已經清楚要標記幾個點了

    今天有可能會有 2、3或更多的標記點要標記 但是數量無法確定的情況下
    那要怎麼做會比較好

    回覆刪除
    回覆
    1. 不是太明白你的需求,
      如果每次開啟地圖才去抓資料庫取標記,那數量應該是可以確定的,
      開啟App->資料庫->建標記。

      資料庫取出來的資料存成陣列,迴圈跑一次就建完標記了。
      不知道是不是你要的?

      刪除
    2. 方法跟我用的一樣 但是... 我卡在一個地方
      就是 .. 迴圈跑完解析完陣列之後
      就可以建立標記點

      但.. 假設資料庫資料可能有3筆或更多...(我不知道的情況下)
      但是 他必須自動建立標記點
      要如何做到讓他自動建立 (因為上述都已經清楚知道要建立幾個標記點所以程式碼可以寫死)

      刪除
    3. 假設你建了一個標記值物件
      class MyMarker{
      public LatLng position;
      public String title;
      }

      然後你的資料庫取出來的資料塞給它,並且存在 List 集合(markers)中,你可以用 ArrayList 或 LinkedList :
      List markers = new ArrayList();
      //以下在每取一筆資料庫中的資料時加入,
      markers.add(new MyMarker(new LatLng(25.033611, 121.565000), "台北101"))
      ...
      當你跑完資料庫後,List中就會有所有的資料,
      接著跑一遍 List 建立標記,先建立一個加標記的方法
      public void addMarker(LatLng position, String title){
      MarkerOptions markerOpt = new MarkerOptions();
      markerOpt.position( position );
      markerOpt.title( title );

      mMap.addMarker(markerOpt);
      }
      然後
      for (MyMarker marker : markers){
      addMarker(marker.position, marker.title);
      }
      就完成了,其實你在取資料庫一筆一筆取出來的時候也可以就直接建標記。

      不知道是不是你要的,因為這樣完全是看資料庫取出幾筆資料存在集合中,它就加幾個標記。

      刪除
    4. 謝謝板大的寶貴意見
      這就是我想要解決的方法 我會嘗試看看
      有問題再懇請幫忙!!

      刪除
  17. 您好

    想要請問一下

    v2版的Map

    在MapFragment之下

    地圖是整個螢幕顯示的

    請問要如何指定MapFragment的範圍大小?

    讓地圖可以只在螢幕的某部分顯示?

    謝謝

    回覆刪除
    回覆
    1. 設定 fragment 的 android:layout_width 及 android:layout_height 應該可以吧。例如:200dp
      或是放在 RelativeLayout 中去指定和其他元件的相對關係。

      刪除
  18. 請問一下 在V3版的地圖 要怎麼使用每隔一段時間抓經緯度阿

    回覆刪除
    回覆
    1. 請參考這篇
      http://blog.tonycube.com/2013/06/androidmaps-and-positioning3.html

      刪除
  19. 你好
    我直接下載demo檔案
    可是在main.xml中map-fragment的設定
    第一列跟"map:"開頭的數列都會出現下列錯誤訊息
    Unexpected namespace prefix "map" found for tag fragment
    這是什麼原因呢?
    google過了找不到相關資訊
    還請作者大大解惑
    謝謝!

    回覆刪除
    回覆
    1. 檢查看看 Project -> Build Path 的設定

      可參考
      http://stackoverflow.com/questions/15024430/android-google-maps-fragment-in-the-xml-i-get-unexpected-namespace-prefix
      打勾的解答

      刪除
    2. 不好意思,我也是遇到同樣問題,我自己做上課的範例,沒有問題
      就是指顯示一個google map
      可是我下載您的res-layout-main.xml檔 怕您刪除之前的package api key
      所以我把xml檔直接複製貼上,可是在map屬性以及xmln:http://xxxx.xxx
      這兩行都會有錯誤
      Unexpected namespace prefix "map" found for tag fragment
      可是我的權限設定檔裡面已經有
      android.library.reference.2=../../Androidfor/adt-bundle-windows-x86_64-20140321/sdk/extras/google/google_play_services/libproject/google-play-services_lib
      而且函市庫也有google play service.jar
      而且這是拿,已經成功的範例來修改main.xml檔了
      怎麼還是會出現這種錯誤,程式碼部分沒問題,xml這邊,就很神奇@@?
      PS:我把錯誤部分刪除,就可順利執行。
      PSS. 版主您是用什麼編碼XDD?我自己一值試MS950 ISO8859-1都不是

      刪除
    3. 我不記得有改編碼,應該是預設的MS950。

      Android SDK 及 ADT 版本太零散,同一個專案在不同的 SDK/ADT 上,都有可能出問題。我就曾發生同一個專案隔幾個月後重新打開,期間有更新過 SDK/ADT,就無法編譯了,一個程式碼都沒動過。所以出錯的問題都不會是在程式碼,而有可能是 Library 變了,導致原本的東西找不到或版本不符,通常上 Google 會找到一堆相同問題的解答。

      刪除
  20. 請問一下 我是寫V2 我要畫出定位軌跡的線該如何實現 請版大提示一下 謝謝

    回覆刪除
    回覆
    1. 沒用過 V2 。不過 Google 說不再支援 V2 了,建議還是更新。

      刪除
  21. 在電腦上DEMO的沒問題,可是我把程式轉成APK,安裝到手機後地圖就顯示不出了,有方法解決嗎?

    回覆刪除
    回覆
    1. 1.檢查網路是否正常
      2.手機上必須有Google Play App(基本上都會有)
      3.如果是發佈成APK,確定你有把 Debug 憑證換成 Release 憑證
      請參考第一篇
      http://blog.tonycube.com/2012/12/androidmaps-and-positioning1.html

      刪除
  22. 我想請問遺下如何讓使用者新增一個marker?
    而不是我們程式碼預設的

    回覆刪除
    回覆
    1. 1.抓點擊地圖的座標
      你可以用 GoogleMap.OnMapClickListener (https://developer.android.com/reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener.html),並實作onMapClick(LatLng point)方法,就能取得使用者點擊地圖時的座標。

      2.設定Marker
      MarkerOptions marker = new MarkerOptions();
      marker.position(new LatLng(25.047924, 121.517081));//<==使用者點擊時取得的座標

      mMap.addMarker(marker);

      刪除
  23. 作者已經移除這則留言。

    回覆刪除
    回覆
    1. 不是很懂 marker 不能重複定義的意思。
      先確定你指的MySQL資料庫應該是指遠端的伺服器吧,不是手機內建的SQLite檔案,
      那麼你必須寫一段伺服端的程式去取得資料庫中的資料,整理好之後(依你的需求應該是JSON格式的資料),
      回傳給你的App使用。

      刪除
    2. 作者已經移除這則留言。

      刪除
    3. 在 Java 裡字串比對要用 equals() 方法,
      改成 if ( type.equals("restaurant") )
      其他看起來沒問題,
      要看 DDMS 的 LogCat 給你什麼錯誤訊息。

      刪除
    4. 感謝老師,已經成功

      刪除
    5. 作者已經移除這則留言。

      刪除
  24. 老師,我想問,如果我想加一個搜尋功能,去搜尋Marker ,可以怎樣做?

    回覆刪除
    回覆
    1. 在你建立Marker的同時,可以把 title 存在集合中,
      當使用者輸入文字並按下搜尋按鈕後,去跑一次集合,比對文字,找到相對的 Marker。

      刪除
    2. 作者已經移除這則留言。

      刪除
    3. actionbarsherlock 是非官方套件,現在有官方的 ActionBarCompat (可參考 http://blog.tonycube.com/2014/02/android-actionbarcompat-1.html)

      要用 ActionBarCompat 是為了向下支援,可支援到 2.x 版,如果沒有這個必要,可以不用 ActionBarCompat。
      現在 2.x 版的裝置很少了,建議可以直接使用 Action Bar (http://developer.android.com/guide/topics/ui/actionbar.html)就好。

      要注意的是,只要你要使用支援套件(例如ActionBarCompat),就必須裝 Support Library(http://developer.android.com/tools/support-library/index.html)
      v4通常是必要的,要用到 ActionBar,就必須再加入 v7。

      然後要注意 import 的部份
      import android.support.v7.app.ActionBar 表示使用支援套件
      import android.app.ActionBar 表示使用內建套件 (3.x之後)
      這裡只要 import 錯了,程式就會出錯。

      刪除
    4. 作者已經移除這則留言。

      刪除
    5. 你把兩個地點丟給 Google Directions API ,它會幫你把路徑計算出來,
      以 JSON 的格式回傳,剩下就你自己去對資料做出處理(你放的連結裡的教學,就是把資料中的點畫到地圖上)。

      Google Directions API
      https://developers.google.com/maps/documentation/directions/#JSON

      你如果把它的範例
      http://maps.googleapis.com/maps/api/directions/json?origin=Chicago,IL&destination=Los+Angeles,CA&waypoints=Joplin,MO|Oklahoma+City,OK&sensor=false
      貼到網址上,顯示的就是JSON的資料。

      刪除
  25. Tony老師你好:
    我在學Google Maps Android開發,使用的是mapfragment的方式顯示Google Map。
    我的問題是:如何在mapFragment下增加一個overlay,原因是我看到的都是在Mapview的方式下,通過Overlay類增加圖層;另外,在Google開發者的網頁上,mapFragment下也沒有看到用於增加圖層的相應的類的內容。
    先謝啦,祝快樂一天!

    回覆刪除
    回覆
    1. 指南裡有說到 Overlays 的部份
      https://developers.google.com/maps/documentation/android-api/tileoverlay
      研究看看吧~

      刪除
  26. 老師你好
    請問可以在標記上顯示時間嗎? 謝謝

    回覆刪除
    回覆
    1. 把時間轉成字串放在title裡

      刪除
  27. 你好,我想請問一下如何把標記的經緯度存到SQ資料庫中?

    回覆刪除
    回覆
    1. 經緯度只是數字,直接存到資料庫即可

      刪除
    2. 就是要怎麼讀取到標記的坐標?用什麼語句可以將標記的坐標直接存資料庫,而不是像添加聯繫人那樣輸入到資料庫中。謝謝。

      刪除
    3. pos=marker.getPosition();
      lat=pos.lat();
      lng=pos.lng();

      刪除
  28. 請問 定位 自身的位置 這部分 是哪一段? 我自學要做專題 有點難懂

    回覆刪除
    回覆
    1. 看第(3)篇
      http://blog.tonycube.com/2013/06/androidmaps-and-positioning3.html

      刪除

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。