2015年4月24日

使用 Google Maps Adnroid API v2 完整客製化地圖(二)


由於網路與手機的快速成長,LBS 功能已經漸漸滲入我們的生活中,外出導航、查看門市據點、分享自己的位置資訊等應用越來越多,客製化的要求也越來越高,下面就來解說一下如何完整的客製化 google map
Google Maps Android v1 API 已在 2012/12/3 停用,取代之的就是 Google Maps Adnroid API v2 使用 fragment 來顯示 google map。其實還有 Google Maps JavaScript API v3 做法是在 android webview 中嵌入 html 檔案來顯示 google map,google map 的相關設定當然就是使用 JavaScript 啦!
因為 Google Maps JavaScript API v3 還不是很穩定,所以這裡還是使用舊版的 Google Maps Adnroid API v2 來實現客製化 google map

程式解說

  1. 修改自己位置的 mark
    
    /**
     * 在 map上增加自己的位置
     * @param latLng
     */
    private void addMyLocationIcon(LatLng latLng) {
    GroundOverlayOptions newarkMap = new GroundOverlayOptions().image(
      BitmapDescriptorFactory.fromResource(R.drawable.man1))
      .position(latLng, 94, 200);
    imageOverlay = mGoogleMap.addGroundOverlay(newarkMap);
    }
    

  2. 使用 MarkerOptions 在 map 上顯示自訂地標,可設定地標圖示、名稱等資訊
    
    /**
     * 在map上顯示自訂地標
     * 
     * @param locationInfoList
     */
    public void parseLocationAndShowMap(List locationInfoList) {
    mGoogleMap.clear();
    mapInfoAdapter.setKeyword(false);
    // 標注據點位置 for (LocationInfo locationInfo : locationInfoList) { MarkerOptions markerOptions = new MarkerOptions(); double lat = Double.parseDouble(locationInfo.getLat()); double lng = Double.parseDouble(locationInfo.getLng()); LatLng latLng = new LatLng(lat, lng); markerOptions.position(latLng); String name = locationInfo.getName(); int icon = R.drawable.location; switch (locationInfo.getAtype()) { case 1: // 公司 icon = R.drawable.maxkit; break; case 2: // 客戶 icon = R.drawable.custom; break; case 3: // 自行車道 icon = R.drawable.bicycle; break; default: icon = R.drawable.location; break; } markerOptions.title(name); // map上icon點擊後顯示資料 markerOptions.icon(BitmapDescriptorFactory.fromResource(icon)); // 設定map上顯示的圖示 //建立地標 MarkerHelper markerHelper = new MarkerHelper(locationInfo); String snippet = GsonUtil.gson.toJson(markerHelper); markerOptions.snippet(snippet); mGoogleMap.addMarker(markerOptions); } LatLng latLng = new LatLng(mLatitude, mLongitude); addMyLocationIcon(latLng); }

  3. 繼承 InfoWindowAdapter 類別,並在 getInfoContents 中設定 mark 點擊後顯示畫面
    
    @Override
    public View getInfoContents(Marker marker) {
    // 連結xml中實體物件
    LayoutInflater inflater = (LayoutInflater) context
      .getSystemService(Context.LAYOUTINFLATERSERVICE);
    View infoWindow = inflater.inflate(R.layout.mapinfosbl, null);
    TextView tvtitle = (TextView)infoWindow.findViewById(R.id.tvmapInfotitle);
    TextView tvaddr = (TextView)infoWindow.findViewById(R.id.tvmapInfo_addr);
    TextView tvtel = (TextView)infoWindow.findViewById(R.id.tvmapInfotel);
    ImageView imgvpic = (ImageView)infoWindow.findViewById(R.id.imgvmapInfopic);
    MarkerHelper markerHelper = GsonUtil.gson.fromJson(marker.getSnippet(), MarkerHelper.class);
    //設定title tv_title.setText(marker.getTitle());
    //設定地址 String addr = markerHelper.getAddr(); if(TextUtils.isEmpty(addr)){ tvaddr.setText(""); }else{ tvaddr.setText(addr); }
    //設定電話 String tel = markerHelper.getTel(); if(TextUtils.isEmpty(tel)){ tvtel.setText(""); }else{ tvtel.setText(tel); }
    if(!this.isKeyword){ //關鍵字搜尋不用顯示圖片 imgvpic.setVisibility(View.VISIBLE); Integer path = markerHelper.getPic(); if(path!=null){ imgvpic.setImageResource(path); }else{ Log.i(ConfigUtil.TAG, "no image"); } }else{ imgv_pic.setVisibility(View.GONE); }
    return infoWindow; } @Override public View getInfoWindow(Marker arg0) { return null; }

  4. 設定 map 上 mark,點擊後顯示的畫面
    
    //地圖上 marker 點擊後彈出的畫面
    mapInfoAdapter = new MapInfoAdapter(MainActivity.this, false);
    mGoogleMap.setInfoWindowAdapter(mapInfoAdapter);
    

  5. 設定 InfoWindow 點擊後功能
    
    // map標識
    mGoogleMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
    @Override public void onInfoWindowClick(Marker arg0) { try { MarkerHelper markerHelper = GsonUtil.gson.fromJson( arg0.getSnippet(), MarkerHelper.class); Log.i(ConfigUtil.TAG, "phone:" + markerHelper.getTel()); // 撥打電話 Intent intent = new Intent(Intent.ACTION_CALL, Uri .parse("tel:" + markerHelper.getTel())); startActivity(intent); } catch (Exception e) { Log.e(ConfigUtil.TAG, "Exception:" + e); } } });

  6. 搜尋地標,可分為使用 type, keyword, radar 三種方式 ( 詳細內容可參考 Google Places API Web Service )
    (1) type:
    送出 https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=座標&radius=搜尋範圍&types=種類&sensor=true&key=server api key
    範例:
    
    //呼叫API
    https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=24.1674116,120.6679557&radius=5000&types=bank&sensor=true&key=AIzaSyC9nSWENfNXaPrQ9pMFtvxL5NSwbpMiEE
    
    //回傳 { "htmlattributions" : [], "nextpagetoken" : "CoQC8gAAAB6cvLyq0yHNFy6xoBRrpTVsUCLD2kVsvcSIrXiRRfrnvE9jFUzdq-sRLbKq4Q5bHCrcN1SwayQcDsvsADKuHbx5ucnVZa0l85iAUm9kzGtEiMK1NcJWiHxNe0REVWYwDAz0kXUSlu3rKfR26VNoBORPXxRcagaRfAKHZHqKTplmCOw0gZOR70drr6eZXFGhymSaZ5jSlaoQL9-bel4hfqZOaLekWYpjr9gSI7X-Op66wWpeFKYeVPleA6heArUDBsHt8js4ykSAPRk4I22ikcUonw98BxbZmgAjt6hQd8zuhs5v9QI4046TBpZ0oHNjGzTznWs9vB91BK1hTEAQSEGS91M0wqOcKJHBQBSHhMx8aFLzuXUD3ha6M1ob3VM4-uxeXps8N",
       "results" : [
      {
         "geometry" : {
            "location" : {
               "lat" : 24.161911,
               "lng" : 120.651707
            }
         },
         "icon" : "http://maps.gstatic.com/mapfiles/placeapi/icons/genericbusiness-71.png",
         "id" : "48b7e2d33ccc3897eed4b98fa0ce3ad0654633c2",
         "name" : "星展銀行",
         "openinghours" : {
            "opennow" : false,
            "weekdaytext" : []
         },
         "placeid" : "ChIJex4xo49aTQRuHMhLV-kDc",
         "reference" : "CmRfAAAA0uofNZht6utbASwNmEpMxu39xdoEd9eU65BTDVCoNvbBBsPbYfyZYddBB3cB8PmTGKbJNRXXDu1AdTQorDhjpDKKbJdNHCGlqjx5LKd3RtLTM7ERbuhi-mvCIZTIHrIEhCtERO5biWmTqLdpx-047gDGhT-5qgakVk9fx9sjlRZUfOKpYCZIg",
         "scope" : "GOOGLE",
         "types" : [ "bank", "finance", "establishment" ],
         "vicinity" : "西屯區台中港路二段60之8號"
      },
      {
         "geometry" : {
            "location" : {
               "lat" : 24.147987,
               "lng" : 120.669588
            }
         },
         "icon" : "http://maps.gstatic.com/mapfiles/placeapi/icons/genericbusiness-71.png",
         "id" : "e9adb41f5c16918b9ea7c9e198b5058b5484ff6f",
         "name" : "星展銀行",
         "openinghours" : {
            "opennow" : false,
            "weekdaytext" : []
         },
         "placeid" : "ChIJv2OHQ9aTQRknnvtT9f1us",
         "reference" : "CmRgAAAAt01TuRucNuYv88xttZlznmXKEHfFrdlanQZwkPrjcrVivtumLny9flPaZNy4YF366QsafHJWppMwUTx8bIMgvNrBOpbTTnmeOjLA8oKi4bFuhKq4xHXvYHHufTzjEEhCdP4J1C2m4S4aSfdqY9gbPGhQWkuEgceFvbqhBLyLM5qKBB2uoWw",
         "scope" : "GOOGLE",
         "types" : [ "bank", "finance", "establishment" ],
         "vicinity" : "西區民權路219號"
      },
      ...
      ...
      {
         "geometry" : {
            "location" : {
               "lat" : 24.139748,
               "lng" : 120.677998
            }
         },
         "icon" : "http://maps.gstatic.com/mapfiles/placeapi/icons/genericbusiness-71.png",
         "id" : "ae07416012e09331be83ffbab77779628e0fecc8",
         "name" : "花旗(台灣)商業銀行ATM",
         "openinghours" : {
            "opennow" : false,
            "weekdaytext" : []
         },
         "placeid" : "ChIJq39fRI9aTQR1M2sdNU3nM",
         "reference" : "CnRwAAAA7GlK9vwBW-myUnXTnB2Tv-V5XJVHJQx91CE95VPiS5OJ5ayyCjD4g1x3yiLJcW-1v1bbOaABMXEJHycbXXSKoKzfIjoLlwXIl7l-aEg8-zjOlwjBliaCHsbImHFcJkcunjDhiwjiKhYS3qAiGYhIQDXjcoIVkaEaTsAwmVTRWdBoURb7EUTY-oV9ZCqc3iOvmcwSH9jU",
         "scope" : "GOOGLE",
         "types" : [ "atm", "bank", "finance", "establishment" ],
         "vicinity" : "中區民權路102號"
      }
    ],
    "status" : "OK"
    }
    

    (2) keyword:
    送出 https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=座標&radius=搜尋範圍&keyword=關鍵字&sensor=true&key=server api key
    範例:
    //呼叫 https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=24.1674116,120.6679557&radius=5000&keyword=自行車道&sensor=true&key=AIzaSyC9nSWENfNXaPrQ9pMFtvxL5NSwbpMiEE
    
    //回傳 { "htmlattributions" : [], "results" : [ { "geometry" : { "location" : { "lat" : 24.136734, "lng" : 120.697396 } }, "icon" : "http://maps.gstatic.com/mapfiles/placeapi/icons/genericbusiness-71.png", "id" : "74d4245ed61187f907175744fe5dc6f7c8a4830c", "name" : "東光園道自行車道", "photos" : [ { "height" : 460, "htmlattributions" : [ "\u003ca href=\"https://plus.google.com/102113594474011668675\"\u003e林老頭\u003c/a\u003e" ], "photoreference" : "CuQB1wAAAGcJIdgm3ornEgoy9apsL7UjHTcOEYYIqn1cK55YGn4fajRwP4kKBr25PWm5e9RCKx9HEv0kg4gpTljSJAREsTIh9lOMuOjBxI6aQBP6vmUvaAVUXqfXrHHXoVG2BypVOqAeOYzg3sH1cWa3TM7HrbOUvwJ7VsnGSqMSgiIyrwzUYu-nTdUrGKGPMEeSC5i2eKs9PZhdaovZwogMrlr25yfEUH2C15jXkFtCikTHH7W-U6JYOicwAsHIqNPHqlpw-JuuOReGzxP1dt8rd-frUXqhFgYQR1X7k1KeiMYcEhCWlvdamFzPz0eQxPFkZcDwGhQ20ycIsDLytFbMsGshU4N-SCvNPw", "width" : 816 } ], "placeid" : "ChIJgfDC9Dg9aTQRyJmwVbF12E", "rating" : 3.8, "reference" : "CnRrAAAA8rDOWN4IVcqYfzLmpU4lKFFLTCXo339Cm6rC1wg7kAgrS8SpDdeZudwNqkBRzgGs-NqbNm5SZKMnfjzn49ZPYlaUw53Kq-T3WVs466PTKJ51Ia1O91iDrJq5SF1lIvAmvCwqBIb3BIC5UFVdBhIQE4XQTI07iOK2lD13zm1ZphoUFT7FDj4Cgk29BaxOgYULua5wgyk",
         "scope" : "GOOGLE",
         "types" : [ "establishment" ],
         "vicinity" : "東區東光園路446之1號"
      },
      {
         "geometry" : {
            "location" : {
               "lat" : 24.171131,
               "lng" : 120.704385
            }
         },
         "icon" : "http://maps.gstatic.com/mapfiles/placeapi/icons/genericbusiness-71.png",
         "id" : "e4351c405528bfc1085af05445aaa25cedb428ed",
         "name" : "旱溪「親水式」自行車道",
         "placeid" : "ChIJJxfG4AXaTQRq2DOJE0wrDQ",
         "reference" : "CoQBdAAAAHiN0alkLB-3xj8Haqef71asoPLBDS9w-klUH1t1bQceMEl44sYtDG3iETmj97DBRyllHrgLBUYy2Pd66ds30kGs751xNA1FCOQvV6SqAV2tiwoAZ1R5XP1YkfnajraCGD3gXXmXLuQgx26mPvXwYyPwHyIQkFNJRbajsGub0EhDJHlsfFvE81ShEVDuqgzUFGhSy14J6FaRXHZn0rX1ttQFkffkmbg",
         "scope" : "GOOGLE",
         "types" : [ "establishment" ],
         "vicinity" : "台中市北屯區旱溪西路三段"
      },
      ...
      ...
      {
         "geometry" : {
            "location" : {
               "lat" : 24.157597,
               "lng" : 120.65739
            }
         },
         "icon" : "http://maps.gstatic.com/mapfiles/placeapi/icons/restaurant-71.png",
         "id" : "fd211ebe704db2dc4889e293768a2c98d461d784",
         "name" : "燒烤王",
         "photos" : [
            {
               "height" : 1224,
               "htmlattributions" : [
                  "\u003ca href=\"https://plus.google.com/117051252423976960156\"\u003e葵小\u003c/a\u003e"
               ],
               "photoreference" : "CnRoAAAAak-SYbk7I2xCIeNUONEVbjK4DpcxD5Qd4b45skXbLARZ2DrY1Gq2vQDOf7Ygc1Zn2k2ejpUvbc7xrfqBHdwg8tSoK2aPIhj3pRPCipbKPPm9DirAveduwC5fJm0xbgihevYSSCaHaXvsOzVn5ThIQ46Hl6qTeGvOgI8wkRvGN-hoUkuVqKONKwuid4QCeup5pqxgGEk",
               "width" : 1632
            }
         ],
         "placeid" : "ChIJfYieKps9aTQR7X7CLRNl940",
         "rating" : 3.9,
         "reference" : "CmRdAAAAj2ixVlTCAPfNZlwSfsfIS1Sh1n-5Pj6nyCGYqe5ruArp9lYPS-neb0UOnMeG0WBlKIHdDNW84eUht3KXIKyliRuqRWgcrfstRghXwNT-sqg5QSug3mMyqAnEcUxhEhA0T0qNLxjHmiyc1BgwbUchGhQDJw8fYPLzbjcpHex2ESjQu-V4A",
         "scope" : "GOOGLE",
         "types" : [ "restaurant", "food", "establishment" ],
         "vicinity" : "西屯區精誠路8號"
      }
    ],
    "status" : "OK"
    }
    

執行結果截圖




Refecnes

範例下載
※ 執行前請先將 Manifest.xml 中的 com.google.android.maps.v2.APIKEY ( android api key ) 與 ConfigUtil 中的 APIKEYGOOGLEMAP ( server api key ) 換掉