百度地图之定位图层

时间:2020-12-03 09:06:28

使用百度地图结合GPS进行定位一文中,我们已经介绍了利用GPS结合百度地图进行定位,另外我们也可以使用百度SDK里面集成的方法,直接进行定位,这样就不需要我们自己去写GPS定位的方法了,代码原型来自百度Demo,代码如下:

Activity:

package com.home;

import android.app.Activity;
import android.content.Context;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.RadioGroup.OnCheckedChangeListener;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.map.LocationData;
import com.baidu.mapapi.map.MapController;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationOverlay;
import com.baidu.mapapi.map.PopupClickListener;
import com.baidu.mapapi.map.PopupOverlay;
import com.baidu.platform.comapi.basestruct.GeoPoint;

/**
* 此demo用来展示如何结合定位SDK实现定位,并使用MyLocationOverlay绘制定位位置 同时展示如何使用自定义图标绘制并点击时弹出泡泡
*
*/
public class LocationOverlayActivity extends Activity {

// 定位相关
LocationClient mLocClient;
LocationData locData = null;
public MyLocationListenner myListener = new MyLocationListenner();

// 定位图层
locationOverlay myLocationOverlay = null;
// 弹出泡泡图层
private PopupOverlay pop = null;// 弹出泡泡图层,浏览节点时使用
private TextView popupText = null;// 泡泡view
private View viewCache = null;

// 地图相关,使用继承MapView的MyLocationMapView目的是重写touch事件实现泡泡处理
// 如果不处理touch事件,则无需继承,直接使用MapView即可
MyLocationMapView mMapView = null; // 地图View
private MapController mMapController = null;

// UI相关
OnCheckedChangeListener radioButtonListener = null;
Button requestLocButton = null;
boolean isRequest = false;// 是否手动触发请求定位
boolean isFirstLoc = true;// 是否首次定位

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_locationoverlay);
CharSequence titleLable = "定位功能";
setTitle(titleLable);
requestLocButton = (Button) findViewById(R.id.button1);
OnClickListener btnClickListener = new OnClickListener() {

@Override
public void onClick(View v) {
// 手动定位请求
requestLocClick();
}
};
requestLocButton.setOnClickListener(btnClickListener);

RadioGroup group = (RadioGroup) this.findViewById(R.id.radioGroup);
radioButtonListener = new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId == R.id.defaulticon) {
// 传入null则,恢复默认图标
modifyLocationOverlayIcon(null);
}
if (checkedId == R.id.customicon) {
// 修改为自定义marker
modifyLocationOverlayIcon(getResources().getDrawable(
R.drawable.icon_geo));
}
}
};
group.setOnCheckedChangeListener(radioButtonListener);

// 地图初始化
mMapView = (MyLocationMapView) findViewById(R.id.bmapView);
mMapController = mMapView.getController();
mMapView.getController().setZoom(14);
mMapView.getController().enableClick(true);
mMapView.setBuiltInZoomControls(true);
// 创建 弹出泡泡图层
createPaopao();

// 定位初始化
mLocClient = new LocationClient(this);
locData = new LocationData();
mLocClient.registerLocationListener(myListener);
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true);// 打开gps
option.setCoorType("bd09ll"); // 设置坐标类型
option.setScanSpan(5000);
mLocClient.setLocOption(option);
mLocClient.start();

// 定位图层初始化
myLocationOverlay = new locationOverlay(mMapView);
// 设置定位数据
myLocationOverlay.setData(locData);
// 添加定位图层
mMapView.getOverlays().add(myLocationOverlay);
myLocationOverlay.enableCompass();
// 修改定位数据后刷新图层生效
mMapView.refresh();

}

/**
* 手动触发一次定位请求
*/
public void requestLocClick() {
isRequest = true;
mLocClient.requestLocation();
Toast.makeText(LocationOverlayActivity.this, "正在定位……",
Toast.LENGTH_SHORT).show();
}

/**
* 修改位置图标
*
* @param marker
*/
public void modifyLocationOverlayIcon(Drawable marker) {
// 当传入marker为null时,使用默认图标绘制
myLocationOverlay.setMarker(marker);
// 修改图层,需要刷新MapView生效
mMapView.refresh();
}

/**
* 创建弹出泡泡图层
*/
public void createPaopao() {
viewCache = getLayoutInflater()
.inflate(R.layout.custom_text_view, null);
popupText = (TextView) viewCache.findViewById(R.id.textcache);
// 泡泡点击响应回调
PopupClickListener popListener = new PopupClickListener() {
@Override
public void onClickedPopup(int index) {
Log.v("click", "clickapoapo");
}
};
pop = new PopupOverlay(mMapView, popListener);
MyLocationMapView.pop = pop;
}

/**
* 定位SDK监听函数
*/
public class MyLocationListenner implements BDLocationListener {

@Override
public void onReceiveLocation(BDLocation location) {
if (location == null)
return;

locData.latitude = location.getLatitude();
locData.longitude = location.getLongitude();
// 如果不显示定位精度圈,将accuracy赋值为0即可
locData.accuracy = location.getRadius();
locData.direction = location.getDerect();
// 更新定位数据
myLocationOverlay.setData(locData);
// 更新图层数据执行刷新后生效
mMapView.refresh();
// 是手动触发请求或首次定位时,移动到定位点
if (isRequest || isFirstLoc) {
// 移动地图到定位点
mMapController.animateTo(new GeoPoint(
(int) (locData.latitude * 1e6),
(int) (locData.longitude * 1e6)));
isRequest = false;
}
// 首次定位完成
isFirstLoc = false;
}

public void onReceivePoi(BDLocation poiLocation) {
if (poiLocation == null) {
return;
}
}
}

// 继承MyLocationOverlay重写dispatchTap实现点击处理
public class locationOverlay extends MyLocationOverlay {

public locationOverlay(MapView mapView) {
super(mapView);
}

@Override
protected boolean dispatchTap() {
// 处理点击事件,弹出泡泡
popupText.setBackgroundResource(R.drawable.popup);
popupText.setText("我的位置");
pop.showPopup(BMapUtil.getBitmapFromView(popupText), new GeoPoint(
(int) (locData.latitude * 1e6),
(int) (locData.longitude * 1e6)), 8);
return true;
}

}

@Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}

@Override
protected void onResume() {
mMapView.onResume();
super.onResume();
}

@Override
protected void onDestroy() {
// 退出时销毁定位
if (mLocClient != null)
mLocClient.stop();
mMapView.destroy();
super.onDestroy();
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mMapView.onSaveInstanceState(outState);

}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mMapView.onRestoreInstanceState(savedInstanceState);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
return true;
}

}

/**
* 继承MapView重写onTouchEvent实现泡泡处理操作
*
* @author Administrator
*
*/
class MyLocationMapView extends MapView {
static PopupOverlay pop = null;// 弹出泡泡图层,点击图标使用

public MyLocationMapView(Context context) {
super(context);
}

public MyLocationMapView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public MyLocationMapView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
if (!super.onTouchEvent(event)) {
// 消隐泡泡
if (pop != null && event.getAction() == MotionEvent.ACTION_UP)
pop.hidePop();
}
return true;
}
}

地图工具类:

package com.home;

import android.graphics.Bitmap;
import android.view.View;

public class BMapUtil {

/**
* 从view 得到图片
*
* @param view
* @return
*/
public static Bitmap getBitmapFromView(View view) {
view.destroyDrawingCache();
view.measure(View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.setDrawingCacheEnabled(true);
Bitmap bitmap = view.getDrawingCache(true);
return bitmap;
}
}


配置文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.home"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="10" />
<!-- 使用网络功能所需权限 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" >
</uses-permission>

<!-- 读取手机的当前状态权限,没有的话会报错,这个是使用百度地图API必须的 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
</uses-permission>

<!-- Cache功能需要读写外部存储器 ,若没这个权限,地图加载不出来 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>
<!-- 使用GPS需要的权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!--
添加屏幕支持
android:anyDensity="true"
这个属性指明应用程序是否包含了能够适用于任何屏幕密度的资源。
对于支持Android1.6(API Level 4)和更高版本的应用程序,这个属性的默认值是true,
并且除非绝对的确认这是应用程序正常工作所必须的,否则不应该把它设置为false。
只是在应用程序直接操作位图时才需要禁止这个属性。

android:largeScreens="true"
这个属性用于指示应用程序是否支持较大外形的屏幕。
一个large类型的屏幕被定义成一个比normal类型的手持设备的屏幕明显还要大的屏幕,
并且为了让应用程序能够良好的使用,使用这个属性时要特别小心,尽管可以依赖系统来调整尺寸,
以便能够填充屏幕。
这个属性的默认值实际上在某些版本之间是不同的,因此最好在任何时候都明确的声明这个属性。
如果设置为false,系统会启用屏幕兼容模式,这时要格外的小心。

android:normalScreens="true"
这个属性用于指示应用程序是否支持普通外形的屏幕。
典型的是HVGA中等密度的屏幕,但是WQVGA低密度和WVGA高密度屏幕也被认为是普通屏幕。
这个属性的默认值是true。

android:smallScreens="true"
这个属性用于指定应用程序是否支持较小外形的屏幕。
一个small类型的屏幕被定义成一个比normal(传统的HVGA)类型的屏幕还要小的屏幕。
外部服务(如Google Play)不会把不支持小屏的应用程序提供给小屏设备,
因为很少有能够确保该应用程序在小屏幕的设备上正常工作的平台。这个属性的默认值是true。

android:resizeable="true"
这个属性用于指示针对不同的屏幕尺寸,应用程序是否可以调整尺寸。默认值是true。
-->
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true" />

<application
android:name="com.home.DemoApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.home.LocationOverlayActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
</service>
</application>

</manifest>

注意:该配置文件与之前的有个区别,多了一个service,它是百度jar包下的一个服务类,这是定位必须要的,不然就不能定位。

Application类同之前一样。

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<com.home.MyLocationMapView
android:id="@+id/bmapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginTop="80dip"
android:background="#D000"
android:minWidth="100dip"
android:orientation="vertical"
android:padding="2dp" >

<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="定位icon" >

<RadioButton
android:id="@+id/defaulticon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="默认图标" >
</RadioButton>

<RadioButton
android:id="@+id/customicon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="自定义图标" >
</RadioButton>
</RadioGroup>
</LinearLayout>

<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="25dp"
android:layout_marginTop="10dip"
android:background="@drawable/custom_loc" />

</RelativeLayout>

custom_text_view.xml:

<?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:orientation="horizontal" >

<TextView
android:id="@+id/popleft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/popup_side"
android:gravity="center"
android:text="更新位置"
android:textColor="#3814ed"
android:textSize="12sp"
android:textStyle="bold" />

<LinearLayout
android:id="@+id/popinfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >

<TextView
android:id="@+id/textcache"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/popup_middle"
android:gravity="center"
android:textColor="@android:color/black"
android:textSize="12sp"
android:textStyle="bold" />

<TextView
android:id="@+id/popdown"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/popup_down"
android:textColor="@android:color/black"
android:textSize="12sp" />
</LinearLayout>

<TextView
android:id="@+id/popright"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/popup_side"
android:gravity="center"
android:text="更新marker"
android:textColor="#3814ed"
android:textSize="12sp"
android:textStyle="bold" />

</LinearLayout>

附上图片效果:

百度地图之定位图层