基于Google地图的 地图定位

时间:2023-02-15 01:07:24

原理

在Android应用中调用Google Map服务主要依赖于MapView、MapController、GeoPoint这三个API,掌握了它们的用法之后,接下来就可以在Android中开发较复杂的Map相关的应用了。 在使用google地图时,可以看到地图上常用图钉或小气球来标记位置。Google Maps 是通过在地图上添加层,然后再在这个图层上面添加标记来实现此功能的。Android提供了多个类来实现在地图上添加层。实现此类功能的一个关键类是Overlay,也可以使用此类的扩展类ItemizedOverlay。 在地图当中使用标记的步骤:

  1. 继承自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()方法,在其内部编写点击标记的事件 处理代码
  2. 在MapActivity类中创建自定义图层类的对象
  3. 创建标记对象
  4. 将标记对象添加到图层的指定位置
  5. 将自定义图层添加到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所示。 基于Google地图的 地图定位

示例:在地图上标注中日韩三国的首都。

第一步:修改主布局文件的代码如下所示:

<?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;
	}
}

运行程序,结果如下图 所示: 基于Google地图的 地图定位

示例:利用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;
	}
}

运行程序,结果如下图所示: 基于Google地图的 地图定位