上一篇中,已經實現了對地圖的一些基本的簡單操作,現在要實現以下幾個功能:
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 展示的bitmapposition
- 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 展示的 viewposition
- 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點擊效果