編輯:關於Android編程
在開發地圖的應用中,我們很多時候需要在地圖上繪制一些文本,圖標信息(比如當前位置的圖標,比如某個區域內肯德基店的所有興趣點)
為了能夠在地圖上繪制我們需要的信息(比如圖片),我們需要知道圖層的概念。(就像photoshop裡的圖層)
接下來我們需要利用API接口實現我們的功能(我們這裡采用的是高德的API,高德API開發包可自行在官網上下載)
高德API提供了一個基類Overlay,用於在地圖上繪圖。我們可以繼承自該類,重寫draw()方法,調用canvas(畫布)的一些方法(比如drawText,drawCircle,drawBitmap),可以在地圖上畫出許多圖形來。這些東西在上一章中有過介紹就不在啰嗦了。
API裡還有一個抽象類,它叫做ItemizedOverlay<OverlayItem>,它繼承自Overlay,所以它也是一個圖層類。該類最大的特點是,它可以描繪出一組興趣點(POI)出來。繼承該抽象類,必須復寫三個方法,首先是一個構造方法,它含有一個參數Drawable,該參數是一個圖形資源,實則上就是負責顯示在地圖上的一個圖標。另外兩個方法分別是
[java]
@Override
protected OverlayItem createItem(int i) {
}
@Override
public int size() {
}
方法createItem中的返回類型是OverlayItem,該類封裝有地理點(GeoPoint),片段信息(Snippet)以及標題(Title),我們通常是這樣來得到一個OverlayItem對象的:
[java]
OverlayItem item = new OverlayItem(gp, "title","snippet");//gp的類型是GeoPoint
在講第二個方法前,我們首先看看如何繼承ItemizedOverlay<OverlayItem>,假設實現類名為DemoItemizedOverlay
在自己的實現類中,對於字段,我們需要添加一個List<OverlayItem>列表:
[java
List<OverlayItem> overlay_list = new ArrayList<OverlayItem>();
注意該列表的元素類型是OverlayItem。
接下來是重寫構造方法:
[java]
public DemoItemizedOverlay(Drawable d) {
super(boundCenterBottom(d));
}
方法boundCenterBottom的作用是為了將(0,0)點置於圖標的底邊中點。
而方法boundCenter的作用是將(0,0)置於圖標中央。
然後是重寫兩個必寫方法:
[java]
@Override
protected OverlayItem createItem(int i) {
return over_list.get(i);
}
@Override
public int size() {
return over_list.size();
}
如果想在圖標附近添加文本,我們需要復寫draw方法:
[java]
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
for(int i=0; i< size(); i++) {
OverlayItem item = createItem(i);
GeoPoint gp = item.getPoint();
Point mPoint = new Point();
Projection proj = mapView.getProjection();
proj.toPixels(gp, mPoint);
Paint mPaint = new Paint();
mPaint.setColor(Color.BLUE);
mPaint.setAntiAlias(true); //抗鋸齒
canvas.drawText("圖標" + (i+1), mPoint.x, mPoint.y-30, mPaint);
}
super.draw(canvas, mapView, shadow);
}
注意到列表內容是空的,我們需要增加方法來向列表添加內容和刪除內容
[java]
* 添加一個Overlay
*/
public void addOverlay(OverlayItem overlay) {
over_list.add(overlay);
populate();
}
/**
* 刪除一個Overlay
*/
public void dropOverlay(OverlayItem item) {
if(over_list.contains(item)) {
over_list.remove(item);
populate();
}
}
關鍵點來了,有沒有注意到populate()方法,我們可以看看該方法的定義位置:
[java]
void com.amap.mapapi.map.ItemizedOverlay.populate()
說明該方法是ItemizedOverlay類裡的。
我們看看官方文檔是怎麼描述該方法的。
[html]
在一個新的ItemizedOverlay對象上執行所有操作的工具方法。子類通過createItem(int)方法提供item。一旦有了數據,子類在調用其它方法前,首先調用該方法。
我們在回過頭來看看那兩個必寫方法,createItem()和size()方法。
當我們在向列表裡添加或者刪除(各種操作)方法後,必須首先調用populate()方法。調用populate()方法後,接下來就會自動調用createItem()方法和size()方法,這樣列表裡才真正有了數據。為了驗證這一點,我自己做了一個測試。
測試大概是這樣的, 我首先創建了DemoItemizedOverlay對象,然後創建了4個OverlayItem對象,接著調用方法addOverlay把它們加入到列表中。如果addOverlay方法裡含有populate()方法,那麼在測試地圖上,我們可以看到有4個圖標以及文本信息。然後如果我把populate()方法刪掉,此時會拋出異常終止信息,查看LogCat日志:
之所以會拋出空指針異常,是因為沒有調用populate()方法,所以也不會調用createItem()方法,因此雖然調用了addOverlay方法,但是實際上並沒有往列表裡添加Overlay,因此會拋出NullPointerException。
我們看下createItem方法的描述:
[plain]
createItem
protected abstract Item createItem(int i)
子類通過該方法創建實體item。該item只能從populate()開始調用,並且緩存起來待以後使用。
參數:
i - 實體item對象。
返回:
創建的實體item。
下面是測試的MainActivity代碼:
[java]
package com.example.itemizedoverlaytest;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.Toast;
import com.amap.mapapi.core.GeoPoint;
import com.amap.mapapi.core.OverlayItem;
import com.amap.mapapi.map.ItemizedOverlay;
import com.amap.mapapi.map.MapActivity;
import com.amap.mapapi.map.MapController;
import com.amap.mapapi.map.MapView;
import com.amap.mapapi.map.Overlay;
import com.amap.mapapi.map.Projection;
public class MainActivity extends MapActivity {
private MapView mapView;
private Drawable d;
private MapController controller;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//this.setMapMode(MAP_MODE_VECTOR); //設置為矢量圖s
setContentView(R.layout.activity_main);
mapView = (MapView)findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true); //開啟縮放控件
controller = mapView.getController(); //得到控制對象
// mapView.setSatellite(true); //設置衛星模式
GeoPoint gp = new GeoPoint((int) (30.227123 * 1E6),
(int) (120.040687 * 1E6)); //工大
controller.setCenter(gp);
controller.setZoom(10);
d = getResources().getDrawable(R.drawable.marker_gpsvalid);
// d.setBounds(0, 0, right, bottom)
List<Overlay> map_list = mapView.getOverlays();
DemoItemizedOverlay demo = new DemoItemizedOverlay(d, this);
GeoPoint gp1 = new GeoPoint((int) (30.227123 * 1E6),
(int) (120.040687 * 1E6));
OverlayItem item1 = new OverlayItem(gp1, "title1","snippet1");
demo.addOverlay(item1);
GeoPoint gp2 = new GeoPoint((int) (30.237123 * 1E6),
(int) (120.050687 * 1E6));
OverlayItem item2 = new OverlayItem(gp2, "title2","snippet2");
demo.addOverlay(item2);
GeoPoint gp3 = new GeoPoint((int) (30.247123 * 1E6),
(int) (120.060687 * 1E6));
OverlayItem item3 = new OverlayItem(gp3, "title3","snippet3");
demo.addOverlay(item3);
map_list.add(demo);
GeoPoint gp4 = new GeoPoint((int) (30.257123 * 1E6),
(int) (120.070687 * 1E6));
OverlayItem item4 = new OverlayItem(gp4, "title4","snippet4");
demo.addOverlay(item4);
demo.dropOverlay(item2);
}
public class DemoItemizedOverlay extends ItemizedOverlay<OverlayItem> {
private List<OverlayItem> over_list = new ArrayList<OverlayItem>();
private Context mContext; //上下文
public DemoItemizedOverlay(Drawable d) {
super(boundCenterBottom(d));
}
public DemoItemizedOverlay(Drawable d,Context c) {
this(d);
mContext = c;
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
for(int i=0; i< size(); i++) {
OverlayItem item = createItem(i);
GeoPoint gp = item.getPoint();
Point mPoint = new Point();
Projection proj = mapView.getProjection();
proj.toPixels(gp, mPoint);
Paint mPaint = new Paint();
mPaint.setColor(Color.BLUE);
mPaint.setAntiAlias(true); //抗鋸齒
canvas.drawText("圖標" + (i+1), mPoint.x, mPoint.y-30, mPaint);
}
super.draw(canvas, mapView, shadow);
}
@Override
protected boolean onTap(int i) {
OverlayItem item = over_list.get(i);
Toast.makeText(mContext,"片段信息:" + item.getSnippet() + "\n標題:" + item.getTitle(),Toast.LENGTH_SHORT).show();
return super.onTap(i);
}
@Override
protected OverlayItem createItem(int i) {
return over_list.get(i);
}
@Override
public int size() {
return over_list.size();
}
/**
* 添加一個Overlay
*/
public void addOverlay(OverlayItem overlay) {
over_list.add(overlay);
populate();
}
/**
* 刪除一個Overlay
*/
public void dropOverlay(OverlayItem item) {
if(over_list.contains(item)) {
over_list.remove(item);
populate();
}
}
}
}
最後別忘了加相應的權限,以及在安卓清單文件中注冊該Activity。
需要項目資源的可點擊:http://download.csdn.net/detail/czjuttsw/4726692
先給大家展示下效果圖,如果感覺不錯,請參考實現思路:我們要實現一個自定義的再一個圓形中繪制一個弧形的自定義View,思路是這樣的: 先要創建一個類ProgressVie
趁著周一休息,更新一下博客。最近項目中使用到了分組管理,需要實現Listview的Item拖動處理。查略一下資料和借鑒了別人的代碼將功能實現了。現在整理一下代碼,方便自己
以前在使用ListView當中,如果我們的列表數據發生了改變,我們會去調用Adapter.notifyDataSetChanged()去更新UI界面上的列表數據,當然這個
下面我們把這個控件內嵌到Layout中做一些動畫和展示,效果圖: 這個子控件可以上下移動,可以左右滑動,如果上下滑動距離大於左右滑動距離,則必須上下滑動 @Ove