Google Map API v2 (三)----- 地圖上添加標記(Marker),標記info窗口,即指定經緯度獲取地址字符串


 

接上篇 http://www.cnblogs.com/inkheart0124/p/3536322.html

1,在地圖上打個標記

 1 private MarkerOptions mMarkOption;
 2 
 3 mMarkOption = new MarkerOptions().icon(BitmapDescriptorFactory.fromAsset("target.png"));
 4 mMarkOption.draggable(true);
 5 
 6 double dLat = mLocation.getLatitude();
 7 double dLong = mLocation.getLongitude();
 8 
 9 LatLng latlng = new LatLng(dLat, dLong);
10 
11 mMarkOption.position(latlng);
12 mMarkOption.title("title");
13 mMarkOption.snippet("snippet");
14 Marker mMarker = mMapView.addMarker(mMarkOption);

3行,MarkerOptions對象,自己設置一個icon( target.png

4行,設置為可拖動

6~9行,構造當前經緯度的LatLng

11~13行,設置標記的位置,info window的標題title、詳細snippet

14行,GoogleMap的 addMarker(MarkerOptions) 方法,把標記添加到地圖上,返回Marker對象mMarker。

 

2,拖動標記

設置標記可拖動:

方法一、先設置mMarkOption.draggable(true);,再addMarker;

方法二、Marker的setDraggable(boolean)方法;

 

Google Map 默認長按標記開始拖動,開發者只需要注冊監聽。注冊拖動事件監聽

mMapView.setOnMarkerDragListener(this);

acitiviy實現OnMarkerDragListener接口如下:

 1 /* OnMarkerDragListener start */
 2 @Override
 3 public void onMarkerDrag(Marker marker) {
 4 }
 5 
 6 @Override
 7 public void onMarkerDragEnd(Marker marker) {
 8 }
 9 
10 @Override
11 public void onMarkerDragStart(Marker marker) {
12     if(marker.isInfoWindowShown())
13         marker.hideInfoWindow();
14         mMarkerLoaded = false;
15     }
16 /* OnMarkerDragListener  end */

3行,public void onMarkerDrag(Marker marker),當Marker拖動的過程中會不斷調用此函數,拖動中marker的位置marker.getPosition()可以得到經緯度。

7行,public void onMarkerDragEnd(Marker marker),拖動結束

11行,public void onMarkerDragStart(Marker marker),開始拖動

11~15行,開始拖動的時候,判斷如果正在顯示info window,則隱藏info window。

 

3,點擊標記彈出info window

點擊marker的default動作就是顯示info window,之前設置的title和snippet會顯示在infowindow中。

我們對info window做一點小改造,讓他顯示一個小圖標和標記地點的地址

代碼:

activity 實現InfoWindowAdapter接口(implements InfoWindowAdapter)

調用GoogleMap的方法setInfoWindowAdapter()方法

mMapView.setInfoWindowAdapter(this);

activity中實現InfoWindowAdapter的兩個方法:

public View getInfoWindow(Marker marker);返回的View將用於構造整個info window的窗口

public View getInfoContents(Marker marker);返回的View將用於構造info window的顯示內容,保留原來的窗口背景和框架

首先需要定義一個View的布局

res/layout/map_info.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 
 3 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 4     android:layout_width="wrap_content"
 5     android:layout_height="wrap_content"
 6     >
 7     
 8     <ImageView 
 9         android:id="@+id/map_info_image"
10         android:layout_width="wrap_content"
11         android:layout_height="wrap_content"
12         android:layout_alignParentLeft="true"
13         android:layout_marginLeft="0dip"
14         android:layout_marginTop="0dip"
15         />
16     
17     <LinearLayout 
18         android:layout_toRightOf="@id/map_info_image"
19         android:layout_width="200dip"
20         android:layout_height="wrap_content"
21         android:layout_marginLeft="5dip"
22         android:layout_marginTop="0dip"
23         android:orientation="vertical"
24         >
25         <TextView 
26             android:id="@+id/map_info_title"
27             android:layout_width="wrap_content"
28             android:layout_height="wrap_content"
29             android:text="map_info_title"
30             android:layout_gravity="center"
31             />
32         
33        <TextView 
34             android:id="@+id/map_info_snippet"
35             android:layout_width="wrap_content"
36             android:layout_height="wrap_content"
37             android:text="map_info_snippet"
38             android:layout_gravity="center"
39             />
40         
41     </LinearLayout>
42     
43 </RelativeLayout>

 

實現getInfoContents函數:

 1 /* GoogleMap.InfoWindowAdapter begin */
 2 private View mInfoWindowContent = null;
 3 @Override
 4 public View getInfoContents(Marker marker) {
 5         
 6     if(mInfoWindowContent == null){
 7         mInfoWindowContent = mInflater.inflate(R.layout.map_info, null);
 8     }
 9         
10     ImageView infoImage = (ImageView)mInfoWindowContent.findViewById(R.id.map_info_image);
11     infoImage.setImageResource(R.drawable.address);
12     TextView infoTitle = (TextView)mInfoWindowContent.findViewById(R.id.map_info_title);
13     infoTitle.setText(marker.getTitle());
14         
15     TextView infoSnippet = (TextView)mInfoWindowContent.findViewById(R.id.map_info_snippet);
16     infoSnippet.setText(marker.getSnippet());
17     return mInfoWindowContent;
18 }
19 
20 @Override
21 public View getInfoWindow(Marker marker) {
22     return null;
23 }

6~8行,根據布局文件 res/layout/map_info.xml 填充一個View的布局

LayoutInflater mInflater = LayoutInflater.from(this); //this即activity的context

10~11行,設置圖標

12~13行,設置title,marker.getTitle()取出marker中保存的title字符串

15~16行,設置snippet,marker.getSnippet()取出marker的snippet字符串

 

當點擊標記彈出info window時,首先會跑到getInfoWindow(),如果返回null,就會跑到getInfoContents(),返回的View就顯示到info window中。

 

4,根據經緯度發查地址,用snippet字段顯示地址信息

首先監聽marker點擊事件

mMapView.setOnMarkerClickListener(this);

activity實現OnMarkerClickListener接口:

/* OnMarkerClickListener start */
@Override
public boolean onMarkerClick(Marker marker) {
    if(mMarkerLoaded == false)
        getAddressOfMarker();
        return false;
}
/* OnMarkerClickListener end */

即,點擊marker,在彈出info窗口前先去查詢marker所在的經緯度的地理地址。

這個函數要返回false。如果返回true,則表示click事件被消費掉了,就不會再觸發默認動作(即彈出info窗口)。

看下google的geocoder反解地址的過程:

private GetAddressTask mGetAddTack = null;
    
private void getAddressOfMarker(){    
    if(mGetAddTack != null){
        mGetAddTack.cancel(true);
    }
    mGetAddTack = new GetAddressTask(this);
    mGetAddTack.execute(mCarMarker.getPosition());
}

getAddressOfMarker函數中執行了一個異步小任務GetAddressTask,代碼如下:

 1 private class GetAddressTask extends AsyncTask<LatLng, Void, String[]>{
 2     Context mContext;
 3         
 4     public GetAddressTask(Context context) {
 5         super();
 6         mContext = context;
 7     }
 8 
 9     @Override
10     protected void onPreExecute(){
11         mMarker.setTitle(getResources().getString(R.string.mapAddrLoading));
12         mMarker.setSnippet(" ");
13         if(mMarker.isInfoWindowShown())
14             mMarker.showInfoWindow();
15     }
16         
17     @Override
18     protected void onPostExecute(String[] result){
19         if(result == null)
20             return;
21             
22         if(mMarker != null){
23             if((result[1] != null) && (result[0] != null)){
24                 mMarker.setTitle(result[0]);
25                 mMarker.setSnippet(result[1]);
26                 if(mMarker.isInfoWindowShown())
27                     mMarker.showInfoWindow();
28                 }
29                 else{
30                     mMarker.setTitle(getResources().getString(R.string.mapAddrTitle));
31                     mMarker.setSnippet(getResources().getString(R.string.mapAddrUnknown));
32                     if(mMarker.isInfoWindowShown())
33                         mMarker.showInfoWindow();
34                     }35                 }
36             }
37             mMarkerLoaded = true;
38         }
39         
40         @Override
41         protected String[] doInBackground(LatLng... params) {
42             LatLng latlng = params[0];
43             String[] result = new String[2];
44     
45             String urlString = "http://maps.google.com/maps/api/geocode/xml?language=zh-CN&sensor=true&latlng=";//31.1601,121.3962";
46             HttpGet httpGet = new HttpGet(urlString + latlng.latitude + "," + latlng.longitude);
47             HttpClient httpClient = new DefaultHttpClient();
48             
49             InputStream inputStream = null;
50             HttpResponse mHttpResponse = null;
51             HttpEntity mHttpEntity = null;
52             try{
53                 mHttpResponse = httpClient.execute(httpGet);
54                 mHttpEntity = mHttpResponse.getEntity();
55                 inputStream = mHttpEntity.getContent();
56                 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
57 
58                 String line = "";
59                 String startTag = "<formatted_address>";
60                 String endTag = "</formatted_address>";
61                 while (null != (line = bufferedReader.readLine())){
62                     if(isCancelled())
63                         break;
64                     line = line.trim();
65                     String low = line.toLowerCase(Locale.getDefault());
66                     if(low.startsWith(startTag)){
67                         int endIndex = low.indexOf(endTag);
68                         String addr = line.substring(startTag.length(), endIndex);
69                         if((addr != null) && (addr.length() >0)){
70                             result[1] = addr;
71                             result[0] = getResources().getString(R.string.mapAddrTitle);
72                             break;
73                         }
74                     } 
75                 }
76             }
77             catch (Exception e){
78                 log("Exception in GetAddressTask doInBackground():" + e);
79             }
80             finally{
81                 try{
82                     if(inputStream != null)
83                         inputStream.close();
84                 }
85                 catch (IOException e){
86                     log("IOException in GetAddressTask doInBackground():" + e);
87                 }
88             }
89             return result;
90         }
91     }


重點是41行開始的 doInBackground 函數,向google的geocoder發起一個http請求,請求格式如下:

http://maps.google.com/maps/api/geocode/xml?language=zh-CN&sensor=true&latlng=30.1601,121.3922

返回數據可以是JSON或XML,我這里用的是XML,語言中文zh-CN,latlng=緯度,經度

返回的XML腳本,是指定經緯度附近的有效地址,可能不只一個。我們只取第一個<formatted_address></formatted_address>標簽中的字符串,保存在result中。

18行,在任務執行結束的onPostExcute函數中,調用marker.setSnippet(result[1])保存到snippet中,title則根據任務執行情況設置成合適的String。

26~28行,由於這是一個異步任務,地址取回的時候,info窗口可能已經顯示出來了,這時調用showInfoWindow(),getInfoContents函數會重新跑一次,讓窗口顯示最新取到的title和snippet。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM