上一篇中,已经实现了对地图的一些基本的简单操作,现在要实现以下几个功能:
a 在百度地图中间实现一个固定不动的View,类似快的打车软件地图中中间固定不动的View;
b 在地图中间固定不动的View上添加PopupWindow,实现随着地图移动,即时显示当前的位置信息;
c 在百度地图上添加覆盖物Marker与InfoWindow的点击事件,这里分别用3种不同的方式实现;
功能就这么点,开始代码实现:
1.在百度地图中间实现一个固定不动的View,类似快的打车软件地图中中间固定不动的CenterIcon
public class CenterIcon extends View {
public static int w;
public static int h;
public static Bitmap mBitmap;
public static MapView mMapView;
public CenterIcon(Context context,MapView mMapView) {
super(context);
// 设置屏幕中心的图标
mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.current_position);
this.mMapView = mMapView;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 获取屏幕中心的坐标
w = mMapView.getWidth() / 2 - mBitmap.getWidth() / 2;
h = mMapView.getHeight() / 2 ;
canvas.drawBitmap(mBitmap, w, h, null);
}
}
说明:CenterIcon继承View,在屏幕中心画出来,然后在BaseMapActivity中添加以下代码
// 初始化屏幕中心
CenterIcon centerIcon = new CenterIcon(this, mMapView);
getWindow().addContentView(
centerIcon,
new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
2.在地图中间固定不动的 CenterIcon上添加PopupWindow,实现随着地图移动,即时显示当前的位置信息
a 初始化中间弹出窗:
/**
* 初始化中间弹出窗
*/
public void initCenterAddrPop() {
centerInflater = (LayoutInflater) getApplicationContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
centerPopView = centerInflater.inflate(R.layout.pop_map_centure, null,
false);
centerPopWindow = new PopupWindow(centerPopView,
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, false);
// popwindow外面可touch
centerPopWindow.setOutsideTouchable(true);
// 获取两个textview
locationNameTextView = (TextView) centerPopView
.findViewById(R.id.locationName);
locationTipsTextView = (TextView) centerPopView
.findViewById(R.id.locationTips);
}
说明:pop_map_centure.xml 是我们自定义的布局,用来显示当前位置的地理信息。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pop_home_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/location_tips"
android:gravity="center_vertical"
android:maxWidth="1000.0dip"
android:minWidth="40.0dip"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="4"
android:gravity="left|center_vertical"
android:orientation="vertical" >
<TextView
android:id="@+id/locationName"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="1"
android:text="浙江省杭州市余杭区余杭区仓前街道"
android:textColor="#adadad"
android:textSize="13sp" />
<TextView
android:id="@+id/locationTips"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="1"
android:text="浙江省杭州市余杭区余杭区仓前街道"
android:textColor="#adadad"
android:textSize="11sp" />
</LinearLayout>
<ImageView
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_margin="8dp"
android:background="@drawable/location_expand"
android:contentDescription="定位" />
</LinearLayout>
/**
* 显示中间弹出窗
*/
public void showCenterAddrPop(Double latitude, Double longitude,
String name, String address) {
if (name == null || name.length() == 0) {
locationNameTextView.setVisibility(View.GONE);
} else {
locationNameTextView.setVisibility(View.VISIBLE);
locationNameTextView.setText(name);
}
locationTipsTextView.setText(address);
// 设置中心弹出框显示位置
// centerPopWindow.showAtLocation(callShopToSwitchButton,
// Gravity.CENTER,
// 0, -CenterIcon.mBitmap.getHeight());
centerPopWindow.showAtLocation(mMapView, Gravity.CENTER, 0,
-CenterIcon.mBitmap.getHeight());
}
c 百度地图状态改变监听函数setOnMapStatusChangeListener。
// 百度地图状态改变监听函数
mBaiduMap.setOnMapStatusChangeListener(new OnMapStatusChangeListener() {
@Override
public void onMapStatusChangeStart(MapStatus status) {
// updateMapState(status);
}
@Override
public void onMapStatusChangeFinish(MapStatus status) {
updateMapState(status);
}
@Override
public void onMapStatusChange(MapStatus status) {
// updateMapState(status);
}
});
在地图状态改变完成onMapStatusChangeFinish的函数中实现updateMapState(status)。
private void updateMapState(MapStatus status) {
LatLng mCenterLatLng = status.target;
/** 获取经纬度 */
myCentureLatitude = mCenterLatLng.latitude;
myCentureLongitude = mCenterLatLng.longitude;
LatLng ptCenter = new LatLng(myCentureLatitude, myCentureLongitude);
mSearch.reverseGeoCode(new ReverseGeoCodeOption().location(ptCenter));
}
这里实现OnGetGeoCoderResultListener( 地理编码/反地理编码结果)接口,重写 反地理编码查询结果回调函数:void onGetReverseGeoCodeResult(ReverseGeoCodeResult result),调用上面的showCenterAddrPop,就可以实现及时的显示屏幕中心的位置信息了。
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
T.showLong(getApplicationContext(), "抱歉,未能找到结果");
return;
}
showCenterAddrPop(myCentureLatitude, myCentureLongitude,
result.getBusinessCircle(), result.getAddress());
}
这是我们实现的效果图(Android5.0.1亲测):
3.在百度地图上添加添加覆盖物Marker与InfoWindow的点击事件,这里分别用3种不同的方式实现
a 先定义几个地理位置信息,这里方便演示,直接写死了,在实际项目中,换一下即可。
OverlayInfo.java
public class OverlayInfo implements Serializable {
private double latitude;
private double longitude;
private String name;
public static List<OverlayInfo> infos = new ArrayList<OverlayInfo>();
static {
infos.add(new OverlayInfo(120.141306, 30.258157, "酒店"));
infos.add(new OverlayInfo(120.2000, 30.250057, "商场"));
infos.add(new OverlayInfo(120.221306, 30.2598157, "西湖"));
infos.add(new OverlayInfo(120.165000, 30.250007, "美食街"));
}
public OverlayInfo(double longitude,double latitude, String name) {
super();
this.latitude = latitude;
this.longitude = longitude;
this.name = name;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/location_tips"
android:orientation="horizontal" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon_location" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="杭州"
android:textColor="#6B6B6B"
android:textSize="13sp" />
</LinearLayout>
就是简单的定义了一张图片和一行文字信息。
c 初始化百度地图上的覆盖物Marker。
/**
* 初始化覆盖物Marker
*/
public void addInfosOverlay() {
// mBaiduMap.clear();
LatLng latLng = null;
OverlayOptions overlayOptions = null;
Marker marker = null;
for (OverlayInfo ovinfo : OverlayInfo.infos) {
// 位置
latLng = new LatLng(ovinfo.getLatitude(), ovinfo.getLongitude());
L.i(TAG, "ovinfo.getLatitude():" + ovinfo.getLatitude()
+ "ovinfo.getLongitude():" + ovinfo.getLongitude());
// 图标
overlayOptions = new MarkerOptions().position(latLng)
.icon(mIconMaker).zIndex(5);
marker = (Marker) (mBaiduMap.addOverlay(overlayOptions));
Bundle bundle = new Bundle();
bundle.putSerializable("Overlayinfo", ovinfo);
marker.setExtraInfo(bundle);
}
}
d 对百度地图上的Marker添加点击时间,弹出InfoWindow。
// 对Marker的点击
mBaiduMap.setOnMarkerClickListener(new OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
// return setInfoWindowClickOne(marker);
// return setInfoWindowClickTwo(marker);
return setInfoWindowClickThree(marker);
}
});
说明:这里分别用了3种方式实现,前两种是对InfoWindow自定义了布局文件,第三种只是简单设置了button.setBackgroundResource(R.drawable.popup);
第一种: 通过传入的 bitmap descriptor 构造一个InfoWindow。使用BitmapDescriptorFactory.fromView(View view),根据一个 View 创建 Bitmap 描述信息, 当 view 为 null 时返回 null。
public InfoWindow(BitmapDescriptor bd, LatLng position, int yOffset, InfoWindow.OnInfoWindowClickListener listener)
通过传入的 bitmap descriptor 构造一个 InfoWindow。
-
参数:
-
bd
- InfoWindow 展示的bitmap -
position
- InfoWindow 显示的地理位置 -
yOffset
- InfoWindow Y 轴偏移量 -
listener
- InfoWindow 点击监听者
public boolean setInfoWindowClickOne(Marker marker) {
// 第一种: 通过传入的 bitmap descriptor 构造一个
// InfoWindow。使用BitmapDescriptorFactory.fromView(View view),根据一个 View 创建
// Bitmap 描述信息, 当 view 为 null 时返回 null
/*
* public InfoWindow(BitmapDescriptor bd, LatLng position, int yOffset,
* InfoWindow.OnInfoWindowClickListener listener) 参数: bd - InfoWindow
* 展示的bitmap position - InfoWindow 显示的地理位置 yOffset - InfoWindow Y 轴偏移量
* listener - InfoWindow 点击监听者
*/
final OverlayInfo ovinfo = (OverlayInfo) marker.getExtraInfo().get(
"Overlayinfo");
LayoutInflater pointInflater = (LayoutInflater) getApplicationContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View pointPopView = pointInflater.inflate(R.layout.pop_map_maker, null,
false);
TextView tv_name = (TextView) pointPopView.findViewById(R.id.tv_name);
tv_name.setText(ovinfo.getName());
BitmapDescriptor bd = BitmapDescriptorFactory.fromView(pointPopView);
// 将marker所在的经纬度的信息转化成屏幕上的坐标
final LatLng ll = marker.getPosition();
Projection mProjection = mBaiduMap.getProjection();
if (mProjection == null) {
return false;
}
Point p = mBaiduMap.getProjection().toScreenLocation(ll);
L.i(TAG, "p.x=" + p.x);
L.i(TAG, "p.y=" + p.y);
p.y -= 47;
LatLng llInfo = mBaiduMap.getProjection().fromScreenLocation(p);
// 为弹出的InfoWindow添加点击事件
InfoWindow pointWindow = new InfoWindow(bd, llInfo, -47,
new InfoWindow.OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick() {
// 隐藏InfoWindow
// mBaiduMap.hideInfoWindow();
T.showLong(getApplicationContext(), ovinfo.getName());
}
});
mBaiduMap.showInfoWindow(pointWindow);
return true;
}
第二种:直接给View设置点击事件
使用
public InfoWindow(View view, LatLng position, int yOffset)
通过传入的 view 构造一个 InfoWindow, 此时只是利用该view生成一个Bitmap绘制在地图中。
-
参数:
-
view
- InfoWindow 展示的 view -
position
- InfoWindow 显示的地理位置 -
yOffset
- InfoWindow Y 轴偏移量
public boolean setInfoWindowClickTwo(Marker marker) {
// 第二种:
/*
* public InfoWindow(View view, LatLng position, int yOffset)通过传入的 view
* 构造一个 InfoWindow, 此时只是利用该view生成一个Bitmap绘制在地图中。 直接给View设置点击事件
*/
final OverlayInfo ovinfo = (OverlayInfo) marker.getExtraInfo().get(
"Overlayinfo");
LayoutInflater pointInflater = (LayoutInflater) getApplicationContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View pointPopView = pointInflater.inflate(R.layout.pop_map_maker, null,
false);
pointPopView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
T.showLong(getApplicationContext(), ovinfo.getName());
}
});
TextView tv_name = (TextView) pointPopView.findViewById(R.id.tv_name);
tv_name.setText(ovinfo.getName());
BitmapDescriptor bd = BitmapDescriptorFactory.fromView(pointPopView);
// 将marker所在的经纬度的信息转化成屏幕上的坐标
final LatLng ll = marker.getPosition();
Projection mProjection = mBaiduMap.getProjection();
if (mProjection == null) {
return false;
}
Point p = mBaiduMap.getProjection().toScreenLocation(ll);
L.i(TAG, "p.x=" + p.x);
L.i(TAG, "p.y=" + p.y);
p.y -= 47;
LatLng llInfo = mBaiduMap.getProjection().fromScreenLocation(p);
// 构造InfoWindow
InfoWindow pointWindow = new InfoWindow(pointPopView, llInfo, -47);
// 显示InfoWindow
mBaiduMap.showInfoWindow(pointWindow);
return true;
}
第三种 这种不能自定义弹出的InfoWindow布局
public boolean setInfoWindowClickThree(Marker marker) {
// 第三种:这种不能自定义弹出的InfoWindow布局
final OverlayInfo ovinfo = (OverlayInfo) marker.getExtraInfo().get(
"Overlayinfo");
Button button = new Button(getApplicationContext());
button.setBackgroundResource(R.drawable.popup);
button.setText(ovinfo.getName());
final LatLng ll = marker.getPosition();
Projection mProjection = mBaiduMap.getProjection();
if (mProjection == null) {
return false;
}
BitmapDescriptor bd = BitmapDescriptorFactory.fromView(button);
Point p = mBaiduMap.getProjection().toScreenLocation(ll);
L.i(TAG, "p.x=" + p.x);
L.i(TAG, "p.y=" + p.y);
p.y -= 47;
LatLng llInfo = mBaiduMap.getProjection().fromScreenLocation(p);
InfoWindow pointWindow = new InfoWindow(bd, llInfo, -47,
new InfoWindow.OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick() {
// 隐藏InfoWindow
// mBaiduMap.hideInfoWindow();
T.showLong(getApplicationContext(), ovinfo.getName());
}
});
mBaiduMap.showInfoWindow(pointWindow);
return true;
}
e 地图单击事件,隐藏弹出InfoWindow
mBaiduMap.setOnMapClickListener(new OnMapClickListener() {
@Override
public boolean onMapPoiClick(MapPoi arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onMapClick(LatLng arg0) {
mBaiduMap.hideInfoWindow();
}
});
最后看一下弹出的InfoWindow点击效果