本教程將探討如何使用谷歌地圖API來顯示出信息點(POI),並使用手機提供的定位服務,來顯示當前位置可搜索到的POI位置。這種情況下,我們應使用商場作為POI。
在本教程的第一部分,我們討論瞭如何使用的MapView和實現位置監聽器獲得您的當前位置。在這一節中,我們將擴展上一節的內容,以顯示你的當前位置和一些信息點(POI)的位置。我們將通過使用一個由Jeff Gifelt開發出來的外部的庫。如果你還沒有完成的上一節的教程,我強烈建議你先完成它。不過,如果你決定不,你也可以使用源文件為起點,開始本節的教程。
你應該註意到在上一節的教程中,我們已經介紹瞭如何獲取你的當前位置。在這一節中,我們將直接編碼位置佛羅裡達大學(這僅僅是為瞭本教程,所以在這區域我們可以顯示商場)。
由於我們將繼續從上一節的教程開始,所以你應該打開該項目。
步驟1:顯示位置信息
上一節最後一步,我們完成顯示我們當前所在的位置,在此階段讓我們擴展顯示瞭一些有關我們的當前位置的信息,如經度和緯度。
這個信息將被顯示為半透明黑色背景的MapView頂部附近的白色文字。
打開的佈局文件(main.xml),在位於MallFinder > res > layout > main.xml
在MapView結束標記之後,FrameLayout結束標記之前,添加下面的代碼:
01
<LinearLayout
02
android:orientation="horizontal"
03
android:layout_width="fill_parent"
04
android:layout_height="wrap_content"
05
android:id="@+id/infoLinearLayout"
06
android:clickable="true"
07
android:onClick="centerToCurrentLocation">
08
<TableLayout
09
android:layout_width="fill_parent"
10
android:layout_height="wrap_content"
11
android:layout_marginTop="30dp"
12
android:background="#97000000"
13
android:padding="7sp">
14
<TableRow>
15
<TextView
16
android:layout_width="fill_parent"
17
android:layout_height="wrap_content"
18
android:layout_weight="1"
19
android:text="@string/latitude"
20
android:id="@+id/latitudeText"
21
android:textColor="#FFFFFF">
22
</TextView>
23
<TextView
24
android:layout_width="fill_parent"
25
android:layout_height="wrap_content"
26
android:layout_weight="1"
27
android:text="@string/longitude"
28
android:id="@+id/longitudeText"
29
android:textColor="#FFFFFF">
30
</TextView>
31
</TableRow>
32
<TableRow>
33
<TextView
34
android:layout_width="fill_parent"
35
android:layout_height="wrap_content"
36
android:layout_weight="1"
37
android:text="@string/accuracy"
38
android:id="@+id/accuracyText"
39
android:textColor="#FFFFFF">
40
</TextView>
41
<TextView
42
android:layout_width="fill_parent"
43
android:layout_height="wrap_content"
44
android:layout_weight="1"
45
android:text="@string/provider"
46
android:id="@+id/providerText"
47
android:textColor="#FFFFFF">
48
</TextView>
49
</TableRow>
50
</TableLayout>
51
</LinearLayout>
你可能已經註意到LinearLayout指定瞭onclick方法,這方法用於半透明的LinearLayout被選中時,讓MapView中心圍繞在用戶的當前位置。如果用戶決定滾動的MapView想迅速返回其當前位置,這是很有用的。
在上述文件中,引用的一些字符串(以android:text=”@string…”開頭的),這些字符串還沒有創建,讓我們的現在創建。
打開位於MallFinder > res > values > strings.xml 的strings.xml文件,並添加以下幾行代碼。
1
<string name="latitude">Latitude : </string>
2
<string name="longitude">Longitude : </string>
3
<string name="accuracy">Accuracy : </string>
4
<string name="provider">Provider : </string>
現在我們已經更新瞭用戶界面,讓我們更新MallFinderActivity.java類代碼來顯示我們的位置坐標。
打開MallFinderActivity.java文件,並在getLastLocation方法中添加以下代碼:
1
((TextView)findViewById(R.id.providerText)).setText("Provider :" + getBestProvider());
更新setCurrentLocation方法包括以下行:
1
((TextView)findViewById(R.id.latitudeText)).setText("Latitude : " + String.valueOf((int)(location.getLatitude()*1E6)));
2
((TextView)findViewById(R.id.longitudeText)).setText("Longitude : " + String.valueOf((int)(location.getLongitude()*1E6)));
3
((TextView)findViewById(R.id.accuracyText)).setText("Accuracy : " + String.valueOf(location.getAccuracy()) + " m");
最後,添加下面的方法:
1
public void centerToCurrentLocation(View view){
2
animateToCurrentLocation();
3
}
如果你現在運行應用程序,你應該看到你當前的緯度、位置、供應商,並且精確的顯示在MapView上。
註意:如果這是首次運行應用程序,經度、緯度和其他地方可能是空白的,直到你的手機可以定位到你的當前位置。這可能需要一些時間,取決於所使用的提供商。
步驟2:使用一個外部庫
我們即將開始在我們的MapView上添加並顯示出當前位置周邊的各個信息點。為瞭這,我們將使用一個由Jeff Gifelt開發定義好的BalloonItemizedOverlay類,位於https://github.com/jgilfelt/android-mapviewballoons。你應該註意到Android有其自身的ItemizedOverlay類,可以用來覆蓋到一個MapView圖形上;但我選擇瞭這個BalloonItemizedOverlay類,是因為它提供瞭按下後彈出一個氣球覆蓋在圖形上的功能,而ItemizedOverlay類默認是沒有該功能的。這也給我們一個機會來看看如何設置並導入外部庫項目到我們自己的項目中。
讓我們開始下載文件 。打開Web瀏覽器輸入https://github.com/jgilfelt/android-mapviewballoons/downloads,點擊“Download as zip”按鈕 。
下載後解壓縮文件,並註意文件的位置。
在Eclipse中,點擊“File > Import”。在新的窗口,選擇“Existing Projects into Workspace”,然後單擊下一步。
在“Select root directory field”項,瀏覽找到解壓縮的BalloonItemizedOverlay文件夾。確保在項目區中有唯一的android-mapviewsballoon項目。然後你可以自由選擇這兩個項目(如果您想包括示例項目),選中復制項目到工作空間復選框。點擊“完成”。
你現在應該看到在Package Explorer窗口中的android-mapviewballoons項目。
選中android-mapviewballoons項目右鍵,選擇“屬性”。彈出一個新窗口。在左邊的列點擊“Android”,右側窗口確保“Is Library”復選框被選中。如果沒有選中,請選中它並點擊應用、確定。
現在你可以在現有的和新建的項目使用這個庫瞭。
我們繼續我們的MallFinder項目前,先導入這個庫。首先,右鍵MallFinder項目,然後屬性,並選擇左側欄“Android”,在右邊窗口找到“Is Library”(跟前面步驟一樣),但這個時候點擊“添加”按鈕,一個新的項目選擇窗口會彈出。選擇android-mapviewballoons,然後單擊“確定”。
步驟3:創建遮罩類
我們現在要創建一個MallOverlay類,它繼承BalloonItemizedOverlay類。在MallFinder > src > com.shawnbe.mallfinder,右鍵點擊com.shawnbe.mallfinder。然後選擇New> Class。命名類名“MallOverlay”,然後單擊“完成”。
我們需要更新MallOverlay類繼承BalloonItemizedOverlay。
1
public class MallOverlay extends BalloonItemizedOverlay<OverlayItem> {
我們還需要導入的幾個項目。所以在MallOverlay.java類的頂部添加以下幾行:
1
import android.graphics.drawable.Drawable;
2
import com.google.android.maps.MapView;
3
import com.google.android.maps.OverlayItem;
4
import com.readystatesoftware.mapviewballoons.BalloonItemizedOverlay;
下一步,我們將需要添加一個構造函數並實現BalloonItemizedOverlay類的一些方法:
註:Eclipse會在可能出錯的情況下通知我們,讓我們很容易地修正錯誤,並添加未實現的方法。
例如,在我們添加瞭構造函數或需要添加一些方法時,你會發現,在“MallOverlay”單詞該行有紅色下劃線。
這表明有錯誤。當你的光標放在“MallOverlay”單詞上,會出現一個信息對話框,讓你知道你必須定義一個構造函數,並提供快速修復。
點擊添加構造函數“MallOverlay(Drawable,MapView)”的鏈接,將會為你添加一個構造函數。
請註意單詞“MallOverlay”仍然存在下劃線。再次將光標懸停在上面,你會看到還有未實現的方法。點擊“添加未實現方法”鏈接,將會為你創建兩個方法。
這是非常重要的一個功能,讓你知道是什麼可能會導致代碼中的錯誤。此功能可以為你節省大量的時間和精力,而不必鍵入每個方法。
MallOverlay類代碼如下:
01
package com.shawnbe.mallfinder;
02
03
import android.graphics.drawable.Drawable;
04
import com.google.android.maps.MapView;
05
import com.google.android.maps.OverlayItem;
06
import com.readystatesoftware.mapviewballoons.BalloonItemizedOverlay;
07
08
public class MallOverlay extends BalloonItemizedOverlay<OverlayItem> {
09
10
public MallOverlay(Drawable defaultMarker, MapView mapView) {
11
super(defaultMarker, mapView);
12
// TODO Auto-generated constructor stub
13
}
14
15
@Override
16
protected OverlayItem createItem(int i) {
17
// TODO Auto-generated method stub
18
return null;
19
}
20
21
@Override
22
public int size() {
23
// TODO Auto-generated method stub
24
return 0;
25
}
26
27
}
現在我們要添加一些功能代碼到上述方法裡。聲明這三個全局變量:
1
private Context mContext;
2
private ArrayList<OverlayItem> malls = new ArrayList<OverlayItem>();
3
private Location currentLocation;
更新和添加在MallOverlay類的方法,代碼如下:
01
public MallOverlay(Drawable defaultMarker, MapView mapView) {
02
super(boundCenter(defaultMarker),mapView);
03
boundCenter(defaultMarker);
04
mContext = mapView.getContext();
05
}
06
07
@Override
08
protected OverlayItem createItem(int i) {
09
// TODO Auto-generated method stub
10
return malls.get(i);
11
}
12
13
@Override
14
public int size() {
15
// TODO Auto-generated method stub
16
return malls.size();
17
}
18
19
public void addOverlay(OverlayItem overlay) {
20
malls.add(overlay);
21
populate();
22
}
23
24
@Override
25
protected boolean onBalloonTap(int index, OverlayItem item) {
26
Toast.makeText(mContext, "Overlay Item " + index + " tapped!",
27
Toast.LENGTH_LONG).show();
28
return true;
29
}
我們現在有瞭一個處理MapView的遮罩圖層的類。
步驟4:顯示當前位置
我們將使用兩種大頭針圖形在地圖上顯示,藍色的大頭針顯示我們當前的位置,而紅色的大頭針顯示周圍的商場。
下載這兩個圖片,並放在你的drawable文件夾裡。由於我采用的是HDPI屏幕,所以我將圖片放在Mallfinder > res > drawable-hdpi文件夾。你應該註意到,當開發應用程序時,因為你不知道用戶的手機屏幕是什麼分辨率的,所以你應該為三種分辨率的屏幕建立一個適當的圖形。這將防止你的圖形被拉伸和收縮,而不會使你的圖形看起來和你預期的不一樣。
下面我們將創建一個方法,讓我們當前的位置呈現在圖像上。
添加下面的方法MallFinderActivity類:
01
public void drawCurrPositionOverlay(){
02
List<Overlay> overlays = mapView.getOverlays();
03
overlays.remove(currPos);
04
Drawable marker = getResources().getDrawable(R.drawable.me);
05
currPos = new MallOverlay(marker,mapView);
06
if(currentPoint!=null){
07
OverlayItem overlayitem = new OverlayItem(currentPoint, "Me", "Here I am!");
08
currPos.addOverlay(overlayitem);
09
overlays.add(currPos);
10
currPos.setCurrentLocation(currentLocation);
11
}
12
}
此外,在onCreate方法中添加下面一行代碼,放在getLastLocation方法和setCurrentLocation方法調用之後。
1
drawCurrPositionOverlay();
運行應用程序,你看到顯示藍色針的地方就是你的當前位置。
步驟5:添加顯示購物中心標記
到目前為止,在我們的教程,我們已經向你展示如何獲得你的當前位置和使用一個圖形標記。然而,為瞭本教程的剩餘部分,我們將直接編碼你的當前位置於佛羅裡達國際大學(FIU)。在我們的例子中,我將圍繞在佛羅裡達國際大學區域周邊的購物中心顯示出來,而不是每次啟動應用程序的時候讓你滾動到該地區。
讓我們現在打開MallFinderActivity類,更新setCurrentLocation方法,如下:
01
public void setCurrentLocation(Location location){
02
/* int currLatitude = (int) (location.getLatitude()*1E6);
03
int currLongitude = (int) (location.getLongitude()*1E6);
04
currentPoint = new GeoPoint(currLatitude,currLongitude); */
05
06
/*========================================================================================
07
/*The Above Code displays your correct current location, but for the sake of the demo
08
I will be hard coding your current location to the University of Florida, to get your real
09
current location, comment or delete the line of code below and uncomment the code above. */
10
11
currentPoint = new GeoPoint(29647929,-82352486);
12
currentLocation = new Location("");
13
currentLocation.setLatitude(currentPoint.getLatitudeE6() / 1e6);
14
currentLocation.setLongitude(currentPoint.getLongitudeE6() / 1e6);
15
16
((TextView)findViewById(R.id.latitudeText)).setText("Latitude : " + String.valueOf((int)(currentLocation.getLatitude()*1E6)));
17
((TextView)findViewById(R.id.longitudeText)).setText("Longitude : " + String.valueOf((int)(currentLocation.getLongitude()*1E6)));
18
((TextView)findViewById(R.id.accuracyText)).setText("Accuracy : " + String.valueOf(location.getAccuracy()) + " m");
19
drawCurrPositionOverlay();
20
}
然後更新getLastLocation方法,如下:
01
public void getLastLocation(){
02
String provider = getBestProvider();
03
currentLocation = locationManager.getLastKnownLocation(provider);
04
05
/*The next 4 lines are used to hardcode our location
06
* If you wish to get your current location remember to
07
* comment or remove them */
08
09
currentPoint = new GeoPoint(29647929,-82352486);
10
currentLocation = new Location("");
11
currentLocation.setLatitude(currentPoint.getLatitudeE6() / 1e6);
12
currentLocation.setLongitude(currentPoint.getLongitudeE6() / 1e6);
13
14
if(currentLocation != null){
15
setCurrentLocation(currentLocation);
16
}
17
else
18
{
19
Toast.makeText(this, "Location not yet acquired", Toast.LENGTH_LONG).show();
20
}
21
((TextView)findViewById(R.id.providerText)).setText("Provider :" + getBestProvider());
22
}
將以下方法添加到MallFinderActivity類,直接編碼一些購物區在佛羅裡達國際大學附近。
01
public void drawMalls(){
02
Drawable marker = getResources().getDrawable(R.drawable.malls);
03
MallOverlay mallsPos = new MallOverlay(marker,mapView);
04
GeoPoint[] mallCoords = new GeoPoint[6];
05
06
//Load Some Random Coordinates in Miami, FL
07
mallCoords[0] = new GeoPoint(29656582,-82411151);//The Oaks Mall
08
mallCoords[1] = new GeoPoint(29649831,-82376347);//Creekside mall
09
mallCoords[2] = new GeoPoint(29674146,-8238905);//Millhopper Shopping Center
10
mallCoords[3] = new GeoPoint(29675078,-82322617);//Northside Shopping Center
11
mallCoords[4] = new GeoPoint(29677017,-82339761);//Gainesville Mall
12
mallCoords[5] = new GeoPoint(29663835,-82325599);//Gainesville Shopping Center
13
14
List<Overlay> overlays = mapView.getOverlays();
15
OverlayItem overlayItem = new OverlayItem(mallCoords[0], "The Oaks Mall", "6419 W Newberry Rd, Gainesville, FL 32605");
16
mallsPos.addOverlay(overlayItem);
17
overlayItem = new OverlayItem(mallCoords[1], "Creekside Mall", "3501 Southwest 2nd Avenue, Gainesville, FL");
18
mallsPos.addOverlay(overlayItem);
19
overlayItem = new OverlayItem(mallCoords[2], "Millhopper Shopping Center", "NW 43rd St & NW 16th Blvd. Gainesville, FL");
20
mallsPos.addOverlay(overlayItem);
21
overlayItem = new OverlayItem(mallCoords[3], "Northside Shopping Center", "Gainesville, FL");
22
mallsPos.addOverlay(overlayItem);
23
overlayItem = new OverlayItem(mallCoords[4], "Gainesville Mall", "2624 Northwest 13th Street Gainesville, FL 32609-2834");
24
mallsPos.addOverlay(overlayItem);
25
overlayItem = new OverlayItem(mallCoords[5], "Gainesville Shopping Center", "1344 N Main St Gainesville, Florida 32601");
26
mallsPos.addOverlay(overlayItem);
27
overlays.add(mallsPos);
28
29
mallsPos.setCurrentLocation(currentLocation);
30
}
我們需要在頁面加載時調用上面的方法。這樣的話,在onCreate方法中,drawCurrPositionOverlay()方法後添加:
1
drawMalls();
運行應用程序,你的當前位置應該在佛羅裡達國際大學,並且在該地區周圍看到5個紅色標記代表的購物中心:
步驟6:顯示相關信息
目前,當你點擊這些標志物之一,它將會給你一些商場的名稱和地址等簡要信息。而我們要添加更多一點的相關信息,比如:我們想顯示出到該商場的距離。
打開位於MallFinder> com.shawnbe.mallfinder> MallOverlay.java的MallOverlay.java文件,並添加下面的方法。此方法接收一個GeoPoint參數並返回一個位置。為瞭使用由Android提供的distanceTo方法,我們需要提供兩個位置作為位置對象,我們的方法會將一個GeoPoint轉換為一個位置對象:
1
public Location convertGpToLoc(GeoPoint gp){
2
Location convertedLocation = new Location("");
3
convertedLocation.setLatitude(gp.getLatitudeE6() / 1e6);
4
convertedLocation.setLongitude(gp.getLongitudeE6() / 1e6);
5
return convertedLocation;
6
}
現在,我們需要更新onBalloonTap方法來計算我們的位置到標記點之間的距離,並用Toast顯示出信息。
更新onBalloonTap方法如下:
01
@Override
02
protected boolean onBalloonTap(int index, OverlayItem item) {
03
String tmp = malls.get(index).getTitle();
04
GeoPoint mallPoint = malls.get(index).getPoint();
05
Location tmpLoc = convertGpToLoc(mallPoint);
06
double distance = ((currentLocation).distanceTo(tmpLoc))*(0.000621371192);
07
DecimalFormat df = new DecimalFormat("#.##");
08
tmp = tmp + " is " + String.valueOf(df.format(distance)) + " miles away.";
09
Toast.makeText(mContext,tmp,Toast.LENGTH_LONG).show();
10
return true;
11
}
現在,當你點擊商城標記點,一些關於名稱和地址的基本信息將顯示在彈出氣球框中。如果你點擊氣球框,Toast將會顯示出該商城標記點與你的距離。
通過本教程,你已經學會如何使用MapView對象,註冊一個API密鑰,獲取你的當前位置,指定你的首選標準供應商,使用外部庫,動態顯示一個位置在MapView上,添加各個信息點在地圖上,甚至添加氣球彈出窗口。我希望本教程信息,能為你提供創建自己的基於位置定位的應用程序所需的知識。如果有些地方不是很清楚,你也可以發送電子郵件給我shawn@shawnbe.com,我會盡我所能幫你弄清楚,或者如果你有任何建議或意見,隨時分享 !
摘自 迷途ф書童的博客