Android 高仿百度地图的LBS服务——基础地图篇(v 3.1.1)



一、前言



转载请标明出处:http://blog.csdn.net/wlwlwlwl015/article/details/41076537

因为项目需要集成地图功能,所以交给我负责研究并继续完善百度地图的部分功能,之前完成了一部分,实现了将我们的数据以Poi的形式标记在地图上以及定位、方向传感器等功能(这部分是鸿洋大神在公司时写的代码 @鸿洋),后来根据需求要加入路线规划功能,即从我们当前的定位点到我们指定的Poi之间要怎么走,比如:通过公交、驾车或步行的方式,所以我就接手之前的代码进行修改和完善,下面就对我这几天学到的和做的东西做个总结和记录,对于新手而言,学习最重要。我的这个Demo是模仿百度地图的,由于模拟器的分辨率、网速和模拟器无法定位等问题,后面会贴出真机的效果图,下面的用模拟器截的动态效果图就凑活看一下哈。

本篇介绍的是基础地图相关的一些内容,路线规划在下一篇blog中记录(模仿百度地图的LBS服务——路线规划篇)



二、项目背景



简单介绍一下我们的项目中需要集成的LBS部分。我们做的是一款旅游方面的APP,数据都是我们采集的特色数据,并以ListView的形式展示,当右滑时切换到地图模式,我们的数据就以Marker的形式展现在地图上,而且要提供路线规划(就是怎么去)的功能,下面是示意图:



点击周边特色功能,可以看到我们推荐的特色数据的ListView,而当进行右滑操作时切换到地图模式,即把我们ListView中的数据展示在地图上,并提供路线规划。下面就按顺序记录一下我这几天对于百度SDK路线规划的学习结果。



三、基础定位、Marker覆盖物、实时路况以及2D/3D的地图模式



这一部分的内容是百度地图SDK相对基本的东西,比较简单,官方的文档和Demo也很到位,之前鸿洋大神的博客也都介绍清楚了,我这里就针对我在使用过程中遇到的问题和觉得重要的地方做一些简单介绍。


1.基础定位


定位可以说是最基本的功能了,我们的项目中需要的是当前定位点到我们特色数据marker点的路径规划,所以定位自然是第一步,先看一下效果图:



可以看到进入程序之后自动定位到当前位置(模拟器无法定位,通过固定坐标模拟了定位的过程),下面贴上代码(整体地图相关功能都写在了一个Fragment中,由于代码过长,所以这里按顺序分段贴出)。

public class MyFragment extends Fragment implements
		OnGetRoutePlanResultListener, BaiduMap.OnMapClickListener,
		OnGetGeoCoderResultListener {

	// Map视图
	private MapView mMapView = null;
	// Map对象
	private BaiduMap mBaiduMap = null;
	// 定位客户端
	private LocationClient mLocationClient = null;
	// 当前定位模式
	private LocationMode mLocationMode = LocationMode.NORMAL;
	// 是否是第一次定位
	private volatile boolean isFristLocation = true;
        // 是否开始定位
        private boolean isStart = false;
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		SDKInitializer.initialize(getActivity().getApplicationContext());
		View view = inflater.inflate(R.layout.activity_main, container, false);

		// Map视图
		mMapView = (MapView) view.findViewById(R.id.bmapView);
		// 初始化定位客户端
		mLocationClient = new LocationClient(getActivity()
				.getApplicationContext());
		return view;
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onActivityCreated(savedInstanceState);
		initMapView();
		addListener();
	}

	@Override
	public void onStart() {
		// TODO Auto-generated method stub
		mBaiduMap.setMyLocationEnabled(true); // 获取是否允许定位图层
		if (!mLocationClient.isStarted()) {
			mLocationClient.start(); // 启动定位sdk
		}
		super.onStart();
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		mBaiduMap.setMyLocationEnabled(false);
		mLocationClient.stop(); // 关闭定位sdk
		mSearch.destroy();// 释放检索实例
		super.onDestroy();
	}

}

需要注意的是定位功能在onStart方法中开启,在onDestroy方法中关闭,这样做的目的是合理控制资源,定位功能不能一直开着,它是很费电的。当开启定位的时候就触发了定位监听器,而在定位之前还需要做一些初始化参数的设置,这部分代码应当写在定位之前,我这里是放在了initMapView()方法中:

private void initMapView() {
	// 初始化Map对象
	mBaiduMap = mMapView.getMap();
	// 设置地图模式(普通模式/卫星模式)
	mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);

	// 设置定位相关配置
	LocationClientOption option = new LocationClientOption();
	option.setCoorType("bd09ll");// 返回的定位结果是百度经纬度,默认值gcj02
	option.setOpenGps(true);// 打开gps
	option.setScanSpan(1000);// 设置发起定位请求的间隔时间为1000ms
	option.setIsNeedAddress(true);// 返回的定位结果包含地址信息
	mLocationClient.setLocOption(option);

	// 初始化覆盖物
	addMarkers();
}

定位监听器实现定位功能:

// 定位监听器
	class MyLocationListener implements BDLocationListener {
		@Override
		public void onReceiveLocation(BDLocation location) {
			// TODO Auto-generated method stub
			// map view 销毁后不在处理新接收的位置
			if (location == null || mMapView == null)
				return;
			isStart = true; // 是否开始定位
			mLocation = location; // 保存定位信息
			// 构造定位数据
			MyLocationData locData = new MyLocationData.Builder()
					.accuracy(location.getRadius())
					// 此处设置开发者获取到的方向信息,顺时针0-360
					.direction(100).latitude(location.getLatitude())
					.longitude(location.getLongitude()).build();
			// 设置定位数据
			mBaiduMap.setMyLocationData(locData);

			// 保存经纬度
			mCurrentAccracy = location.getRadius();
			mCurrentLantitude = location.getLatitude();
			mCurrentLongitude = location.getLongitude();

			// 设置定位图层的配置(定位模式,是否允许方向信息,用户自定义定位图标)
			BitmapDescriptor mCurrentMarker = BitmapDescriptorFactory
					.fromResource(R.drawable.navi_map_gps_locked);

			MyLocationConfiguration config = new MyLocationConfiguration(
					mLocationMode, true, mCurrentMarker);
			mBaiduMap.setMyLocationConfigeration(config);

			// 第一次定位时,将地图位置移动到当前位置
			if (isFristLocation) {
				isFristLocation = false;
				// 得到精度坐标信息
				LatLng ll = new LatLng(location.getLatitude(),
						location.getLongitude());
				LatLng ll1 = new LatLng(34.241743,
						108.969793);
				// 得到地图更新对象
				MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(ll1);
				// 更新地图位置
				mBaiduMap.animateMapStatus(u);
			}
		}
	}

这个回调方法的参数保存了当前的定位信息,最后我给了一个34,108的坐标是为了让模拟器可以加载地图,正常情况下通过location.getXxx去获取就好了。最后两行代码是实现了地图的移动。


最后为定位客户端LocationClient注册定位监听器即可:

mLocationClient.registerLocationListener(new MyLocationListener());


2.Marker覆盖物


marker是Overlay的子类,在百度地图中覆盖物统称为Overlay,它的子类有以下几种:

Arc, Circle, Dot, GroundOverlay, Marker, Polygon, Polyline, Text

它们分别表示不同表现形式的覆盖物,比如:Text表示文字覆盖物等等。

我们用的是Marker覆盖物,由于BaiduMap直接提供了BaiduMap.OnMarkerClickListener,而其他覆盖物没有提供直接的点击事件,所以Marker的变成了我们覆盖物的首选。下面就贴出上面示例图片中添加红色大头针的代码:

	private void addMarkers() {
		List<LatLng> latlngs = new ArrayList<LatLng>();
		latlngs.add(new LatLng(34.24124, 109.013343)); 
		latlngs.add(new LatLng(34.24124, 109.013343));
		latlngs.add(new LatLng(34.27013, 108.938191)); 
		latlngs.add(new LatLng(34.234331, 108.992669)); 
		latlngs.add(new LatLng(34.266885, 108.98974)); 
		latlngs.add(new LatLng(34.241478, 108.969708)); 

		Marker marker = null;
		for (int i = 0; i < latlngs.size(); i++) {
			// 构建Marker图标
			BitmapDescriptor bitmap = BitmapDescriptorFactory
					.fromResource(R.drawable.ic_location_marka);
			// 构建MarkerOption,用于在地图上添加Marker
			OverlayOptions optionoo = new MarkerOptions().position(
					latlngs.get(i)).icon(bitmap);
			// 在地图上添加Marker,并显示
			marker = (Marker) mBaiduMap.addOverlay(optionoo);
			Bundle bundle = new Bundle();
			bundle.putCharSequence("info", "特色数据" + i);
			marker.setTitle("特色数据" + i);
			marker.setExtraInfo(bundle);
		}
	}

可以看到marker还可以存放一些数据,通过setExtraInfo(Bundle bundle)方法存值,那么在OnMarkerClickListener中的回调方法里就可以再通过marker.getExtraInfo()去获取值了。


现在再回到我们的需求,点击marker,弹出marker所在的地点信息并定位到当前marker,当点击marker上的“到这去”按钮,就应当弹出路线规划的选择框,然后绘制路线,下面暂且之放一个点击marker的效果图。由于点击左下角的定位图标的时候没有去模拟固定坐标,所以模拟器也无法获取我的位置信息了。



下面贴一下OnMarkerClickListener的代码:

	// 特色数据的覆盖物点击监听
	class MyMarkerClickListener implements OnMarkerClickListener {
		@Override
		public boolean onMarkerClick(Marker marker) {
			String title = marker.getTitle();
			// 判断title是否为null,特色数据的title不为null,路线节点的title为null
			if (title != null) {
				String info = marker.getExtraInfo().getCharSequence("info")
						.toString();
				// 定位到点击处
				LatLng position = marker.getPosition();
				// 更新当前marker的位置
				MyFragment.this.position = position;
				showPopupWindow(info, R.layout.popup2, R.id.tv_special_data,
						"暂时无法查询到数据");
				MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(position);
				mBaiduMap.animateMapStatus(u);
				return true;
			} else {
				// Do nothing 相当于禁用marker
				return true;
			}

		}

这里还有一个值得一提的小技巧,由于绘制路线中的节点图标也是Marker,和我们自定义的Marker有冲突,所以应当禁用路线节点中的marker的点击事件,通过测试发现路线节点的marker的title是NULL,所以我们在添加覆盖物的时候随意set一个Title就能很好的区分出来,这样也间接实现了禁用路线中的marker的功能,关于路线节点这个东东到后面就知道了。


3.实时路况以及2D/3D/卫星地图模式


这个功能没有什么实质的作用,我这里是纯粹模仿百度地图做的,由于模拟器无法运行这个功能(一点就崩),下面一次贴出真机的效果图和代码,很简单。


首先是实时路况功能,不过根据官方文档看西安市好像还没有开实时路况,但是百度地图貌似也提供了,而且看起来还像那么回事,下班高峰看红线还挺多的(绿线便是畅通,红线表示堵塞)。下面是官方给出已开通实时路况的31个城市(南京,广州,重庆,东莞,长春,台州,福州,金华,北京,常州,杭州,温州,大连,南昌,宁波,沈阳,中山,珠海,佛山,泉州,石家庄,成都,青岛,深圳,武汉,乌鲁木齐,长沙,上海,天津,无锡,厦门)。



代码很简单,就是一个状态开关的开启与关闭而已。

	class MyIsOpenTraffeModeListenerTwo implements OnCheckedChangeListener {
		@Override
		public void onCheckedChanged(CompoundButton buttonView,
				boolean isChecked) {
			if (isChecked) {
				mBaiduMap.setTrafficEnabled(isChecked);
				buttonView.setBackground(getResources().getDrawable(
						R.drawable.btn_img_selector_3_click));
				Toast.makeText(getActivity(), "实时路况已打开", Toast.LENGTH_LONG)
						.show();
			} else {
				mBaiduMap.setTrafficEnabled(isChecked);
				buttonView.setBackground(getResources().getDrawable(
						R.drawable.btn_img_selector_3));
				Toast.makeText(getActivity(), "实时路况已关闭", Toast.LENGTH_LONG)
						.show();
			}
		}

	}


下面是3种地图模式,2D平面/3D模式以及卫星地图,其实2D和3D是二选一的模式,而卫星图模式应当和实时路况一样作为一个选项,但百度地图把这3个做成了一组单选结构,不知道为何这样设计,但我还是这样模仿了,并且修改了3D模式切会卫星模式效果消失的问题:



代码也比较简单,3D图就是将地图的俯仰角设置45°即可。

	class MyRadioGroup4CheckMapModelListener implements
			android.widget.RadioGroup.OnCheckedChangeListener {
		@Override
		public void onCheckedChanged(RadioGroup group, int checkedId) {
			switch (checkedId) {
			case R.id.rb_statellite_mode:
				mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
				break;
			case R.id.rb_normal_mode:
				float overlook = mBaiduMap.getMapStatus().overlook;
				if (overlook < 0) {
					MapStatus ms = new MapStatus.Builder(
							mBaiduMap.getMapStatus()).overlook(45).build();
					MapStatusUpdate u = MapStatusUpdateFactory.newMapStatus(ms);
					mBaiduMap.animateMapStatus(u);
				}
				mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
				break;
			case R.id.rb_three_d_mode:
				MapStatus ms = new MapStatus.Builder(mBaiduMap.getMapStatus())
						.overlook(-45).build();
				MapStatusUpdate u = MapStatusUpdateFactory.newMapStatus(ms);
				mBaiduMap.animateMapStatus(u);
			}
		}

	}



四、总结



本篇blog记录关于百度地图SDK的一些比较基本和简单的功能点,关于篇幅原因重点的路线规划部分将放到下一篇blog中记录(模仿百度地图的LBS服务——路线规划篇)

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
因为最近项目需要,用了3个星期研究了一下百度地图的官方demo,并基于其源代码做了一定的修改,部分模仿了官方版的百度地图V5.3.1(version code: 431,目前最新版是6.0.1)的界面。现放出源代码供大家学习研究,修改版例子中的代码已经尽可能注释了,不过本人水平有限,代码质量可能有待提高,请大家勿用于商业用途,因为可能有很多未知BUG。觉得好的话请大家顶! 开发环境: eclipse:Android Developer Tools Build: v22.0.1-685705 JDK:java version "1.7.0_03" 测试环境: 三星GT-i9228 android2.3.6 主要改动: 1、LayersDemo里面把“普通图、卫星图及交通流量图”集成到了PreferencesActivity里面,修改立即生效。 2、MapControlDemo里面把“缩放级别、旋转、俯视”集成到了PreferencesActivity里面,修改立即生效。把截图功能加到了menu里面。 PS:这里顺便说一下新版百度地图怎么控制俯视角度,我查了好久,连官方的手势说明都没找到,被我无意之间发现了:两只手指同时向下滑为俯视,同时向上为恢复,当然也可以点击地图左上角的指南针 3、UISettingsDemo里面把“缩放、平移、双击放大、旋转” 开关手势功能和显示隐藏“缩放控件、指南针位置”UI控件集,成到了PreferencesActivity里面,修改立即生效。 4、LocationOverlayDemo里面增加了比例尺和自定义缩放控件。 5、OverlayDemo只做了位置修改,下面的两个才是重头戏。 6、RoutePlanDemo模仿百度地图5.3.1的路径规划。 7、OfflineDemo模仿百度地图5.3.1的离线地图,并集成到一个界面了。 如有问题请参照百度文档,或者联系我QQ472950043。 模仿的版本是百度地图5.3.1 ,大家有需要的话可以到豌豆荚下载历史版本里面下载baiduditu_431.apk

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值