12.1.2 Geopoint与MapView
在开始Google Map之前,先来认识下maps包下两个重要的类Geopoint 和MapView 。
Geopoint类是一个不可变类,表示一组经度和纬度值,以微度的整数形式存储。
public 构造方法GeoPoint(int latitudeE6, int longitudeE6)。
用给定的经度和纬度构造一个GeoPoint,单位微度(度* 1E6).
参数:
latitudeE6 - 该点的纬度,为保持Mercator投影精确度,其取值范围是[-80,80]。
longitudeE6 - 该点的经度,可被规范化到(-180, 180)。
public int getLatitudeE6()
返回GeoPoint对象的纬度,单位微度(度* 1E6).
返回值:
纬度.
public int getLongitudeE6()
返回GeoPoint对象的经度,单位微度(度* 1E6)。
返回值:
经度.
一个MapView显示一个由谷歌地图服务获得的数据地图。 当MapView具有焦点时,它将捕捉按键和触摸手势平移和自动缩放地图,包括处理瓷砖更多的地图网络请求。 它还提供了必要的UI元素,为用户控制地图上的所有。 您的应用程序也可以使用MapView类的方法来控制MapView编程和绘制在地图上的覆盖类型。
一般来说,MapView类提供对谷歌地图API的封装,让您的应用程序处理通过类方法谷歌地图数据,它可以让你的地图数据的工作,你将其他类型的意见。
MapView一个查看其中显示的地图(从谷歌地图服务获得的数据)。将捕捉按键和触摸手势平移和缩放地图。 它也可以通过编程方式控制( getController()可以得出一个数Overlay (在上面的地图的getOverlays()
该地图可以显示在一个模式的数量,见setSatellite(boolean) , setTraffic(boolean) ,和setStreetView(boolean) 。 它可以选择性地显示一个“十字线”的时候不是触摸模式,以帮助在使用泛到选择;看到setReticleDrawMode(com.google.android.maps.MapView.ReticleDrawMode) 它也描绘了在左下角的谷歌徽标。
首选变焦机制是内置变焦,见setBuiltInZoomControls(boolean) 。 当用户锅地图,缩放控制会自动在MapView底部所示。
该MapView也是ViewGroup的,让您与附加意见,或者到一个特定的像素偏移,或一个特定的纬度/经度对LayoutParameters。
一个MapView只能建造(或充气)由MapActivity 。 这是因为它依赖于后台线程在网络中进行访问和文件系统中,这些线程必须在牧养的生命周期管理的MapActivity 。 砖是缓存在您的应用程序的目录的文件系统。 高速缓存是自动管理的,这样你就不需要用它做什么,随时可以删除它。
12.1.3 Google Maps实战:漂亮的气泡地图
在地图应用中,我们经常会有对某景点进行查询,显示某景点详细信息的应用需求,这时候如果能在地图上,用手轻轻一按就快速查询,该有多好。接下来,一起来实现这一效果,带气泡的地图。效果如图12-5、图12-6和如图12-7所示。
▲图12-5
地图显示景点位置, ▲图12-6
点击世界之窗后的气泡效果 ▲图12-7
点击锦绣中华后的效果
并以特定图标标识
第一步,先在layout目录下建立一个MapView ,附上申请的Google Maps API Key。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:enabled="true"
android:apiKey="0jFDHBPUJ8bRtUCMX-R9jSPzRj2Gz1Kh879BonA"/>
</RelativeLayout>
第二步,创建一个用来显示气泡的布局View。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/pop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5px"
android:paddingTop="5px"
android:paddingRight="5px"
android:paddingBottom="20px"
>
<TextView android:id="@+id/map_bubbleTitle"
android:ellipsize="marquee"
android:layout_width="120px"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textColor="#000000"
android:textSize="16dip"
android:singleLine="true"/>
<ImageView android:id="@+id/map_bubbleImage"
android:background="@drawable/narrow_select"
android:layout_width="30px"
android:layout_toRightOf="@id/map_bubbleTitle"
android:layout_height="wrap_content"/>
<TextView android:id="@+id/map_bubbleText"
android:layout_width="150px"
android:layout_below="@id/map_bubbleTitle"
android:layout_height="wrap_content"
android:singleLine="false"/>
</RelativeLayout>
第三步,自定义一个ItemizedOverlay用来标识景点的图标和文字的图层。主要对该图层进行重新绘制,来达到想要的效果。
public class MyItemizedOverlay extends ItemizedOverlay<OverlayItem>{
private ArrayList<OverlayItem> overlayItemList = new ArrayList<OverlayItem>();
private Context context;
public MyItemizedOverlay(Context context,Drawable defaultMarker) {
super(defaultMarker);
this.context=context;
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapView, shadow);
// Projection接口用于屏幕像素点坐标系统和地球表面经纬度点坐标系统之间的变换
Projection projection = mapView.getProjection();
// 遍历所有的OverlayItem
for (int index = this.size() - 1; index >= 0; index--) {
// 得到给定索引的item
OverlayItem overLayItem = getItem(index);
// 把经纬度变换到相对于MapView左上角的屏幕像素坐标
Point point = projection.toPixels(overLayItem.getPoint(), null);
Paint paintText = new Paint();
paintText.setColor(Color.RED);
paintText.setTextSize(13);
// 绘制文本
canvas.drawText(overLayItem.getTitle(), point.x + 10, point.y - 15, paintText);
}
}
@Override
protected boolean onTap(int index) {
// TODO Auto-generated method stub
setFocus(overlayItemList.get(index));
return super.onTap(index);
}
@Override
protected OverlayItem createItem(int i) {
return overlayItemList.get(i);
}
@Override
public int size() {
return overlayItemList.size();
}
public void addOverlay(OverlayItem overlayItem) {
overlayItemList.add(overlayItem);
this.populate();
}
}
第四步,实现自己的PopMapActivity,先在地图上根据两景点经纬度创建位置,并以自定义的图标和文字进行标识,给自定义的ItemizedOverlay添加焦点改变事件监听,来完成气泡View的显示和隐藏效果。
public class PopMapActivity extends MapActivity {
/**
* 地图View
*/
protected MapView mapView;
/**
* 弹出的气泡View
*/
private View popView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化气泡,并设置为不可见
popView = View.inflate(this, R.layout.popview, null);
setContentView(R.layout.mymapview);
mapView = (MapView) findViewById(R.id.map_view);
mapView.addView(popView, new MapView.LayoutParams(
MapView.LayoutParams.WRAP_CONTENT,
MapView.LayoutParams.WRAP_CONTENT, null,
MapView.LayoutParams.BOTTOM_CENTER));
// 由于气泡的尾巴是在下边居中的,因此要设置成
MapView.LayoutParams.BOTTOM_CENTER.
// 这里没有给GeoPoint,在onFocusChangeListener中设置
popView.setVisibility(View.GONE);
/**
* 创建图标资源(用于显示在overlayItem所标记的位置)
*/
Drawable drawable = this.getResources().getDrawable(
R.drawable.mis_usemobile);
// 为maker定义位置和边界
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
MyItemizedOverlay overlay = new MyItemizedOverlay(this, drawable);
// 设置显示/隐藏气泡的监听器
overlay.setOnFocusChangeListener(onFocusChangeListener);
/**
* 创建并添加第一个标记:深圳 世界之窗(经度:22.5348 纬度:113.97246)
*/
// 构造一个经纬度点
GeoPoint point = new GeoPoint((int) (22.5348 * 1E6),
(int) (113.97246 * 1E6));
// 创建标记(世界之窗)
OverlayItem overlayItem = new OverlayItem(point, "世界之窗",
"位于中国广东省深圳市南山区华侨城的大型文化旅游景区,是深圳最为著名的旅游景点之一。");
// 将标记添加到图层中(可添加多个OverlayItem)
overlay.addOverlay(overlayItem);
/**
* 创建并添加第二个标记:锦绣中华(经度:22.53108 纬度:113.99151)
*/
point = new GeoPoint((int) (22.53108 * 1E6), (int) (113.99151 * 1E6));
// 创建标记(锦绣中华)
overlayItem = new OverlayItem(point, "锦绣中华",
"中国旅游胜地四十佳之一,是目前世界上最大的实景微缩景区,已入选中国世界纪录协会世界最大实景微缩景区候选世界纪录。 ");
// 将标记添加到图层中(可添加多个OverlayItem)
overlay.addOverlay(overlayItem);
/**
* 往地图上添加自定义的ItemizedOverlay
*/
List<Overlay> mapOverlays = mapView.getOverlays();
mapOverlays.add(overlay);
// 设置地图模式为交通地图
mapView.setStreetView(true);
// 设置启用内置的缩放控件
mapView.setBuiltInZoomControls(true);
/**
* 取得地图控制器对象,用于控制MapView
*/
// 设置地图的中心
mapView.getController().setCenter(point);
// 设置地图默认的缩放级别
mapView.getController().setZoom(13);
}
@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
/**
* 监听器 当一个Overlay焦点改变时触发
*/
private final ItemizedOverlay.OnFocusChangeListener onFocusChangeListener = new ItemizedOverlay.OnFocusChangeListener() {
@Override
public void onFocusChanged(ItemizedOverlay overlay, OverlayItem newFocus)
{
// 创建气泡窗口
if (popView != null) {
popView.setVisibility(View.GONE);
}
if (newFocus != null) {
MapView.LayoutParams geoLP = (MapView.LayoutParams) popView
.getLayoutParams();
geoLP.point = newFocus.getPoint();// 这行用于popView的定位
TextView title = (TextView) popView
.findViewById(R.id.map_bubbleTitle);
title.setText(newFocus.getTitle());
TextView desc = (TextView) popView
.findViewById(R.id.map_bubbleText);
if (newFocus.getSnippet() == null
|| newFocus.getSnippet().length() == 0) {
desc.setVisibility(View.GONE);
} else {
desc.setVisibility(View.VISIBLE);
desc.setText(newFocus.getSnippet());
}
mapView.updateViewLayout(popView, geoLP);
popView.setVisibility(View.VISIBLE);
}
}
};
}
(以上是关于android应用开发全程实录中google map的部分章节,可以看到书的编写方式)