原理
在Android应用中调用Google Map服务主要依赖于MapView、MapController、GeoPoint这三个API,掌握了它们的用法之后,接下来就可以在Android中开发较复杂的Map相关的应用了。 在使用google地图时,可以看到地图上常用图钉或小气球来标记位置。Google Maps 是通过在地图上添加层,然后再在这个图层上面添加标记来实现此功能的。Android提供了多个类来实现在地图上添加层。实现此类功能的一个关键类是Overlay,也可以使用此类的扩展类ItemizedOverlay。 在地图当中使用标记的步骤:
- 继承自ItemizedOverlay<OverlayItem>自定义图层类 a) 在图层类中提供一个 ArrayList<OverlayItem>来保存需要标注到地图上的标记 b) 为图层类增加一个addOverlay(OverlayItem item)方法,用来将OverlayItem添加到 ArrayList中。此处,每添加一个OverlayItem 到ArrayList,都需要调用 populate()方法以读取所有的OverlayItems 并准备画到图层上 c) 修改构造方法,在其内调用super(boundCenterBottom(…))方法将标记放在指定位置 d) 重写createItem(int i)方法,获取参数指定的标记对象 e) 重写size()方法 ,获取标记的总个数 f) 重载构造方法,在其内部对上下文进行赋值 g) 重写onTap()方法,在其内部编写点击标记的事件 处理代码
- 在MapActivity类中创建自定义图层类的对象
- 创建标记对象
- 将标记对象添加到图层的指定位置
- 将自定义图层添加到MapView上进行显示
示例在地图当中通过添加标记Marker的方式标注指定位置。
第一步:修改主布局文件的代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<com.google.android.maps.MapView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/mapView"
android:clickable="true"
android:apiKey="0ZunUBGNC7PX6f_EXkmsJJA1436uoJ3dAsWhXuw" />
</LinearLayout>
第二步:自定义图层类,具体代码如下所示
class FirstOverlay extends ItemizedOverlay<OverlayItem> {
private Context context;//当弹出对话框时使用
//用来保存该图层当中所有的标记对象
private List<OverlayItem> overlayItems = new ArrayList<OverlayItem>();
//第一个参数用于指定标记所使用的默认图片,第二个参数供对话框显示时使用
public FirstOverlay(Drawable defaultMarker , Context context) {
super(boundCenterBottom(defaultMarker)); //将具体显示的点置于图片下方的正*
this.context = context;
}
public FirstOverlay(Drawable defaultMarker) { //这个构造方法必须得重写
super(boundCenterBottom(defaultMarker));
}
//将生成好的OverlayItem对象添加到List当中
public void addOverlay(OverlayItem overlayItem) {
overlayItems.add(overlayItem);
populate();//读取所有的OverlayItem并准备画到图层上
}
@Override
protected OverlayItem createItem(int i) {
return overlayItems.get(i); / /返回第 i 个位置的OverlayItem对象
}
@Override
public int size() {//返回当前OverLay当中所包含的OverlayItem对象的个数
return overlayItems.size();
}
@Override
protected boolean onTap(int index) {//当用户点击标记时触发的操作
OverlayItem item = overlayItems.get(index);
Builder builder = new Builder(context);
builder.setTitle(item.getTitle());
builder.setMessage(item.getSnippet());
Dialog dialog = builder.create();
dialog.show();
return true;
}
}
Activity类的代码如下:
public class UseOverlayItemActivity extends MapActivity{
private MapView mapView ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.useoverlayitem);
mapView = (MapView) findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true); //设置是否启用内置的放大缩小功能
Drawable drawable = getResources().getDrawable(R.drawable.tool);
FirstOverlay firstOverlay = new FirstOverlay(drawable , this);
//GeoPoint通过经纬度指定地图上的点:二七广场
GeoPoint point = new GeoPoint((int)113.6663284*1000000, (int)37.7526144*1000000);
//创建图层上的一个对象
OverlayItem overlayItem = new OverlayItem(point, "你好", "我现在是在哪儿呀");
firstOverlay.addOverlay(overlayItem);
List<Overlay> overlays = mapView.getOverlays();//用于得到所有的图层对象
overlays.add(firstOverlay);
}
@Override
protected boolean isRouteDisplayed() {
return false;
}
}
程序执行的时候,在ItemizedOverlay类的内部,会调用size()方法来确定覆盖项的数量,然后进入循环,为每个项调用createItem(i)。 上面程序中用到的核心方法讲解如下:
public final util.List<Overlay> MapView.getOverlays()
获取当前MapView上的所有的图层组成的列表。 本程序的运行效果如下图10.10所示。
示例:在地图上标注中日韩三国的首都。
第一步:修改主布局文件的代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<com.google.android.maps.MapView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/mapView"
android:clickable="true"
android:apiKey="0ZunUBGNC7PX6f_EXkmsJJA1436uoJ3dAsWhXuw" />
</LinearLayout>
第二步:自定义Overlay图层,具体代码如下所示:
class MyOverlay extends ItemizedOverlay<OverlayItem> {
// 定义要显示的所有标记集合
private List<OverlayItem> list = new ArrayList<OverlayItem>();
private Context context;
public MyOverlay(Drawable defaultMarker) { // 必须重写该构造方法
super(boundCenterBottom(defaultMarker));// 设置标记图片的位置
}
public MyOverlay(Drawable defaultMarker, Context context) {
super(boundCenterBottom(defaultMarker));
this.context = context;
}
// 自定义的方法用来向标记集合中添加标记
public void addOverlayItem(OverlayItem item) {
list.add(item);
populate();// 该方法很重要。将标记显示的功能
}
@Override
protected OverlayItem createItem(int i) {// 重载方法获取当前的第i个标记对象
return list.get(i);
}
@Override
public int size() {// 重载方法获得标记的个数
return list.size();
}
@Override
protected boolean onTap(int index) { // 点击了标记的时候只需的操作
// 显示标记的标题和说明文字
Toast.makeText(context, list.get(index).getTitle() +
list.get(index).getSnippet(),Toast.LENGTH_SHORT).show();
return super.onTap(index);
}
}
第三步:修改Activity类的代码如下所示:
public class MainActivity extends MapActivity {
MapView mapView = null;
MyOverlay myOverlay = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.mapView);
mapView.setClickable(true);
mapView.setBuiltInZoomControls(true);
// 默认的标记图片为中国的国旗
Drawable drawable = getResources().getDrawable(R.drawable.china);
myOverlay = new MyOverlay(drawable, this); // 创建Overlay对象
// 北京的标记
GeoPoint point = new GeoPoint((int) (39.9042140 * 1000000), (int) (116.4074130 * 1000000));
OverlayItem item = new OverlayItem(point, "北京", "这是中国的首都");
myOverlay.addOverlayItem(item);
// 东京的标记
Drawable dongji = getResources().getDrawable(R.drawable.japan);
GeoPoint point2 = new GeoPoint((int) (35.68948750 * 1000000), (int) (139.69170640 * 1000000));
OverlayItem item2 = new OverlayItem(point2, "东京", "这是日本的首都");
// 更改默认的图片为日本 注意必须要调用setBounds方法,否则无效果
dongji.setBounds(0, 0, dongji.getIntrinsicWidth(),
dongji.getIntrinsicHeight());
item2.setMarker(dongji);// 更改默认的标记图片为日本的图片
myOverlay.addOverlayItem(item2); // 加入一个标记对象
// 首尔的经纬度
Drawable korea = getResources().getDrawable(R.drawable.korea);
GeoPoint point3 = new GeoPoint((int) (37.5665350 * 1000000), (int) (126.97796920 * 1000000));
OverlayItem item3 = new OverlayItem(point3, "首尔", "韩国的首都");
korea.setBounds(0,0,korea.getIntrinsicWidth(),korea.getIntrinsicHeight());
item3.setMarker(korea);
myOverlay.addOverlayItem(item3);
// 获得当前mapView的所有overlay集合
List<Overlay> overlays = mapView.getOverlays();
overlays.add(myOverlay);// 将包含三个标记的图层overlay加入到mapview的图层集中
//此处只所以加入控制器,就是为了便于查看程序运行结果
MapController controller = mapView.getController();
controller.animateTo(point2);
controller.setCenter(point2);
controller.setZoom(mapView.getZoomLevel());
}
@Override
protected boolean isRouteDisplayed() {
return false;
}
}
运行程序,结果如下图 所示:
示例:利用Overlay的draw()方法在地图上绘制标记。
第一步:修改主布局文件的代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<com.google.android.maps.MapView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/mapView"
android:clickable="true"
android:apiKey="0ZunUBGNC7PX6f_EXkmsJJA1436uoJ3dAsWhXuw" />
</LinearLayout>
第二步:自定义图层,具体代码如下所示:
class PositonOverlay extends Overlay{
Bitmap bitmap ;
GeoPoint geoPoint;
public PositonOverlay(GeoPoint geoPoint,Bitmap bitmap){
this.geoPoint = geoPoint;
this.bitmap = bitmap;
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapView, shadow);
Projection projection = mapView.getProjection();
Point point = new Point();
projection.toPixels(geoPoint, point);
canvas.drawBitmap(bitmap, point.x, point.y, null);
}
}
第三步:修改Activity类的代码如下所示:
public class GoogleMapTestActivity extends MapActivity {
private MapView mapView = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
GeoPoint geoPoint = new GeoPoint( (int)34.752014421190424*1000000,(int)113.66632941527462*1000000);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tool);
PositonOverlay posOverlay = new PositonOverlay(geoPoint, bitmap)
List<Overlay> list = mapView.getOverlays();
list.add(posOverlay);
}
@Override
protected boolean isRouteDisplayed() {
return true;
}
}
运行程序,结果如下图所示: