Android 程序开发——百度地图的使用(三) 地图定位(定位+跟随+距离测量+地图自适应缩放)

前提:

1. jar包的下载

http://lbsyun.baidu.com/sdk/download?selected=mapsdk_basicmap,mapsdk_searchfunction,mapsdk_lbscloudsearch,mapsdk_calculationtool,mapsdk_radar

只需要选择:基础地图+全量地图即可


2.权限的设置

切记。。。不要忘了服务




------------------------分为初始定位+跟随+距离测量+地图自适应缩放---------------------------


@1初始定位


第一种(推荐)


1.实例化定位服务  和定位注册    一般放在onCreate()函数里

mLocationClient = new LocationClient(getApplicationContext());     //定位初始化
mLocationClient.registerLocationListener(this);//定位注册

2.和它对应的自然是注册的取消  一般放在onDestroy()函数里

mLocationClient.unRegisterLocationListener(this);

3.然后需要定位初始化   ,,把定位的参数一一列出,设置出来,一般是在onCreate()函数里进行

LocationClientOption option = new LocationClientOption();option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备option.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系option.setScanSpan(2000);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要option.setOpenGps(true);//可选,默认false,设置是否使用gpsoption.setLocationNotify(true);//可选,默认false,设置是否当GPS有效时按照1S/1次频率输出GPS结果option.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”option.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到option.setIgnoreKillProcess(false);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死option.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集option.setEnableSimulateGps(false);//可选,默认false,设置是否需要过滤GPS仿真结果,默认需要option.setNeedDeviceDirect(true);mLocationClient.setLocOption(option);

4.此时,开启定位服务,我斟酌好久,选择放在onStart()函数里,项目需要我也放在了onResume()函数里

@Overrideprotected void onStart() {//当Activity调用onStart方法,开启定位以及开启方向传感器,即将定位的服务、方向传感器和Activity生命周期绑定在一起if (!mLocationClient.isStarted()) {mLocationClient.start();//开启定位}super.onStart();}

5.与之对应,即是关闭 关闭定位服务,我推荐onStop()函数里,项目需要 也放在了onPause()里

mLocationClient.stop();

6.如果在使用的过程还需要调用 定位  ,则需要以下代码(不需要则忽略)

mLocationClient.requestLocation();
7.最重要的来了,当你注册定位服务的时候会调用一个接口,会返回一个函数,里面的东西才是最想要用的(经纬度、地区、方向。。。。。。。。。)

//位置信息监听@Overridepublic void onReceiveLocation(BDLocation bdLocation) {// 定位接口可能返回错误码,要根据结果错误码,来判断是否是正确的地址;int locType = bdLocation.getLocType();switch (locType) {case BDLocation.TypeCacheLocation:case BDLocation.TypeOffLineLocation:case BDLocation.TypeGpsLocation:case BDLocation.TypeNetWorkLocation:radius = bdLocation.getRadius();user_latitude = bdLocation.getLatitude();user_longitude = bdLocation.getLongitude();mCurrentX = bdLocation.getDirection();break;default:String s = bdLocation.getLocTypeDescription();break;}}




8.ok当前位置的信息获取完毕,当你已经获取到经纬度以后,,,,接下来就是定位当前位置

//定位到用户当前位置private void showUserLocation() {LatLng latLng = new LatLng(user_latitude, user_longitude);MapStatusUpdate msu  = MapStatusUpdateFactory.newLatLng(latLng);map.animateMapStatus(msu);}
9.也可以在定位的时候放大指定的倍数

//定位到用户当前位置private void showUserLocation() {LatLng latLng = new LatLng(user_latitude, user_longitude);MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(18.0f);// 设置地图放大比例map.setMapStatus(msu);msu = MapStatusUpdateFactory.newLatLng(latLng);map.animateMapStatus(msu);}

第二种,博客里面都是这一套,用户自己斟酌使用


1.定位服务实例化  +   注册监听接口  +  定位初始化,以及参数设置  +  开始定位

 //实例化定位服务,LocationClient类必须在主线程中声明  mLocClient = new LocationClient(getApplicationContext());  mLocClient.registerLocationListener(new BDLocationListenerImpl());//注册定位监听接口  /** * LocationClientOption 该类用来设置定位SDK的定位方式。 */  LocationClientOption option = new LocationClientOption();  option.setOpenGps(true); //打开GPRS  option.setAddrType("all");//返回的定位结果包含地址信息  option.setCoorType("bd09ll");//返回的定位结果是百度经纬度,默认值gcj02  option.setPriority(LocationClientOption.GpsFirst); // 设置GPS优先  option.setScanSpan(5000); //设置发起定位请求的间隔时间为5000ms  option.disableCache(false);//禁止启用缓存定位  
//      option.setPoiNumber(5);    //最多返回POI个数     
//      option.setPoiDistance(1000); //poi查询距离          
//      option.setPoiExtraInfo(true);  //是否需要POI的电话和地址等详细信息          mLocClient.setLocOption(option);  //设置定位参数  mLocClient.start();  // 调用此方法开始定位


2.一套定位返回接口,里面包含各种信息

/** * 定位接口,需要实现两个方法 * @author xiaanming * */  public class BDLocationListenerImpl implements BDLocationListener {  /** * 接收异步返回的定位结果,参数是BDLocation类型参数 */  @Override  public void onReceiveLocation(BDLocation location) {  if (location == null) {  return;  }  StringBuffer sb = new StringBuffer(256);  sb.append("time : ");  sb.append(location.getTime());  sb.append("\nerror code : ");  sb.append(location.getLocType());  sb.append("\nlatitude : ");  sb.append(location.getLatitude());  sb.append("\nlontitude : ");  sb.append(location.getLongitude());  sb.append("\nradius : ");  sb.append(location.getRadius());  if (location.getLocType() == BDLocation.TypeGpsLocation){  sb.append("\nspeed : ");  sb.append(location.getSpeed());  sb.append("\nsatellite : ");  sb.append(location.getSatelliteNumber());  } else if (location.getLocType() == BDLocation.TypeNetWorkLocation){  sb.append("\naddr : ");  sb.append(location.getAddrStr());  }   Log.e("log", sb.toString());  MainActivity.this.location = location;  mLocData.latitude = location.getLatitude();  mLocData.longitude = location.getLongitude();  //如果不显示定位精度圈,将accuracy赋值为0即可  mLocData.accuracy = location.getRadius();  mLocData.direction = location.getDerect();  //将定位数据设置到定位图层里  myLocationOverlay.setData(mLocData);  //更新图层数据执行刷新后生效  mMapView.refresh();  if(isFirstLoc || isRequest){  //将给定的位置点以动画形式移动至地图中心  mMapController.animateTo(new GeoPoint(  (int) (location.getLatitude() * 1e6), (int) (location  .getLongitude() * 1e6)));  showPopupOverlay(location);  isRequest = false;  }  isFirstLoc = false;  }  /** * 接收异步返回的POI查询结果,参数是BDLocation类型参数 */  @Override  public void onReceivePoi(BDLocation poiLocation) {  }  }  
3.经纬度获取到以后,定位到自己的位置

//定位到用户当前位置private void showUserLocation() {LatLng latLng = new LatLng(user_latitude, user_longitude);MapStatusUpdate msu  = MapStatusUpdateFactory.newLatLng(latLng);map.animateMapStatus(msu);}



@2   显示跟随的箭头以及方向的切换(蓝色的小箭头)


第一种方式:百度自带(推荐)

1.设置定位支持,项目需要,我放入了onResume()周期里

map.setMyLocationEnabled(true);

2.与之对应,取消定位支持,我放入onPause()周期里

map.setMyLocationEnabled(false);

3.显示小箭头,这些操作我全部放在了onReceiveLocation(BDLocation bdLocation) 函数里,因为每次返回时得值,可以定时改变小箭头的位置

//位置信息监听@Overridepublic void onReceiveLocation(BDLocation bdLocation) {// 定位接口可能返回错误码,要根据结果错误码,来判断是否是正确的地址;int locType = bdLocation.getLocType();switch (locType) {case BDLocation.TypeCacheLocation:case BDLocation.TypeOffLineLocation:case BDLocation.TypeGpsLocation:case BDLocation.TypeNetWorkLocation:radius = bdLocation.getRadius();user_latitude = bdLocation.getLatitude();user_longitude = bdLocation.getLongitude();mCurrentX = bdLocation.getDirection();MyLocationData data = new MyLocationData.Builder().accuracy(radius).direction(mCurrentX).latitude(user_latitude).longitude(user_longitude).build();map.setMyLocationData(data);MyLocationConfiguration config = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL, true, null);map.setMyLocationConfigeration(config);break;default:String s = bdLocation.getLocTypeDescription();break;}}

此方法采用百度给的方向和经纬度,显示的是百度默认的蓝色小箭头,

这里有两个点:1.蓝色小箭头的替换(自定义图片),2.LocationMode的选择


1.蓝色小箭头替换成自定义图片

代码只需要改两句

MyLocationConfiguration config = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL, true, null);map.setMyLocationConfigeration(config);
原始第三个参数为null,即为默认的图片,即蓝色小箭头

BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromResource(R.mipmap.icon_head);MyLocationConfiguration config = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.NORMAL, true, bitmapDescriptor);map.setMyLocationConfigeration(config);
将null替换成一个自定义的BitmapDescriptor对象即可


2.LocationMode的选择

分为三种:普通模式,跟随模式,罗盘模式

普通模式:简单的显示箭头,以及跟随方向变化,箭头方向变化     MyLocationConfiguration.LocationMode.NORMAL(第一张图)

跟随模式:在普通模式基础之上,无论地图移动到哪里,当返回函数获取到值的时候,立即定位到当前MyLocationConfiguration.LocationMode.FOLLOW  (第一张图)

罗盘模式:有指北针的的方向,类似于3D地图的视角,但不是3D的   MyLocationConfiguration.LocationMode.COMPASS    (第二张图)

                                    



第二种方式:只是改动了方向的获取方式,当时忽略了百度地图,用方向传感器做的,较麻烦,不推荐,供参考


1.开启方向传感器

        //开启方向传感器
//        orientationListener.start();


2.关闭方向传感器

//        orientationListener.stop();//关闭方向传感器

3.方向传感器的调用

//定位结合方向传感器,从而可以实时监测到X轴坐标的变化,从而就可以检测到
//    private void useLocationOrientationListener() {
//        orientationListener = new MapOrientationListener(this);
//        orientationListener.setMapOrientationListener(new MapOrientationListener.onOrientationListener() {
//            @Override
//            public void onOrientationChanged(float x) {//监听方向的改变,方向改变时,需要得到地图上方向图标的位置
//                mCurrentX = x;
//            }
//        });
//    }

4.继承传感器类,重写的方向传感器辅助类

public class MapOrientationListener implements SensorEventListener {private SensorManager mySensorManager;private Sensor mySensor;private Context myContext;private float lastX;private onOrientationListener myOrientationListener;public MapOrientationListener(Context myContext) {//方向传感器的一个构造器super();this.myContext = myContext;}/*** 开启方向传感器*/public void start() {//先通过系统服务来得到传感器管理对象mySensorManagermySensorManager = (SensorManager) myContext.getSystemService(Context.SENSOR_SERVICE);if (mySensorManager != null) {//如果传感器管理对象不为空,则可以通过传感器管理对象来获得方向传感器对象//获得方向传感器对象mySensor = mySensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);}if (mySensor != null) {//如果方向传感器不为空,则给该方向传感器注册监听事件mySensorManager.registerListener(this, mySensor, SensorManager.SENSOR_DELAY_UI);}}/*** 解除注册方向传感器监听事件*/public void stop() {mySensorManager.unregisterListener(this);}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {// TODO Auto-generated method stub}/*** 监听方向发生变化*/@Overridepublic void onSensorChanged(SensorEvent event) {//精度发生改变的时候if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {//如果是方向传感器float x = event.values[SensorManager.DATA_X];//获得传感器的X轴的坐标,可以返回3个值,即X轴的坐标,Y轴坐标,Z轴坐标,我们只需要X轴坐标if (Math.abs(x - lastX) > 1.0) {//对比本次的X坐标的变化比上一次的变化差大于1.0就说明方向发生改变if (myOrientationListener != null) {//说明主界面已经注册了事件,即不为空,然后产生一个回调将实时变化X轴的坐标传入//通过一个回调方法,通知主界面去更新UImyOrientationListener.onOrientationChanged(lastX);//就需要把上一次的X轴坐标传入,在MainActivity中的回调方法中去获取即可}}lastX = x;}}public void setMapOrientationListener(onOrientationListener myOrientationListener) {this.myOrientationListener = myOrientationListener;}//写一个接口实现方向改变的监听产生的回调public interface onOrientationListener {void onOrientationChanged(float x);//回调的方法}
}


@3   距离的测量

百度上提供了很多种,我目前在项目中使用了一种,分享一下

private final static double DEF_PI = 3.14159265359; // PIprivate final static double DEF_2PI = 6.28318530712; // 2*PIprivate final static double DEF_PI180 = 0.01745329252; // PI/180.0private final static double DEF_R = 6370693.5; // 地球半径,m

//根据球面距离计算两点直接的距离public String getLongDistance(double lat1, double lon1, double lat2, double lon2) {double ew1, ns1, ew2, ns2;double distance;// 角度转换为弧度ew1 = lon1 * DEF_PI180;ns1 = lat1 * DEF_PI180;ew2 = lon2 * DEF_PI180;ns2 = lat2 * DEF_PI180;// 求大圆劣弧与球心所夹的角(弧度)distance = Math.sin(ns1) * Math.sin(ns2) + Math.cos(ns1) * Math.cos(ns2) * Math.cos(ew1 - ew2);// 调整到[-1..1]范围内,避免溢出if (distance > 1.0) {distance = 1.0;} else if (distance < -1.0) {distance = -1.0;}// 求大圆劣弧长度distance = DEF_R * Math.acos(distance);if (distance > 1000.0) {DecimalFormat df = new DecimalFormat("0.000");String dis = df.format(distance / 1000);return dis + "km";} else {DecimalFormat df = new DecimalFormat("0.000");String dis = df.format(distance);return dis + "m";}}
上述返回的String类型的,如果需要比较的话,可以转换成Double型,看代码(写的略麻烦,,唉 按需求来)
//最远点的距离(String)longDistance = getLongDistance(user_latitude, user_longitude, max_distance_lat, max_distance_lon);LogUtil.e("hello--------", "最远点的距离:" + longDistance + "\n最远点的坐标" + max_distance_lat + "," + max_distance_lon);String substring = longDistance.substring(0, longDistance.length() - 1);if (substring.substring(substring.length() - 1).equals("k")) {max_distance = Double.parseDouble(substring.substring(0, substring.length() - 1)) * 1000;} else {max_distance = Double.parseDouble(substring.substring(0, substring.length() - 1));}

@4   如何让所有的marker(标记点)“恰好” 全部显示在屏幕上,以自我为中心

1.首先说一下,百度地图的放大倍数和比例尺的关系

private int[] list = new int[]{10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000, 5000000};
对应的放大倍数分别为:20~3;

我的思路:1.首先定位当前  2.计算所有marker 与 自己的距离   3.选择 最大的一个纬度差和最大的一个经度差  4.这样所有的点都可以显示了

1.定位当前

private void showUserLocation() {LatLng latLng = new LatLng(user_latitude, user_longitude);MapStatusUpdate msu  = MapStatusUpdateFactory.newLatLng(latLng);map.animateMapStatus(msu);}
2.计算所有marker与自己的距离,获取最大纬度差和最大经度差

//判断纬度最远的距离if (Math.abs(destination_latitude - user_latitude) > sub_lat) {sub_lat = Math.abs(destination_longitude - user_longitude);max_distance_lat = destination_latitude;}//判断经度最远的距离if (Math.abs(destination_longitude - user_longitude) > sub_lon) {sub_lon = Math.abs(destination_longitude - user_longitude);max_distance_lon = destination_longitude;}

3.计算最大的距离值

//最远点的距离(String)longDistance = getLongDistance(user_latitude, user_longitude, max_distance_lat, max_distance_lon);LogUtil.e("hello--------", "最远点的距离:" + longDistance + "\n最远点的坐标" + max_distance_lat + "," + max_distance_lon);String substring = longDistance.substring(0, longDistance.length() - 1);if (substring.substring(substring.length() - 1).equals("k")) {max_distance = Double.parseDouble(substring.substring(0, substring.length() - 1)) * 1000;} else {max_distance = Double.parseDouble(substring.substring(0, substring.length() - 1));}


4.计算level,显示对应比例

for (int i = 0; i < list.length; i++) {if (max_distance > list[i]) {scale--;}}//定位当前,并放大适应的比例LatLng latLng = new LatLng(user_latitude, user_longitude);MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(scale + 2f);// 设置地图放大比例map.setMapStatus(msu);msu = MapStatusUpdateFactory.newLatLng(latLng);map.animateMapStatus(msu);


最后这个例子有一些偏差,希望会的朋友提醒一下,thanks   ,官方那个setToZoom先不使用








本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部