我们经常需要在地图上显示一些特别的东西,比如一些服务如银行,KFG,学校等等,这样就需要使用POI搜索,基本上的步骤如下
//POI搜索 private MyPoiOverlay mTrafficOverLay;// 交通图层 private MyPoiOverlay mSchoolOverLay;// 学校图层 private MyPoiOverlay mLiveOverLay;// 生活图层 private PoiSearch mPoiSearch;//搜索服务 private float latitude = 31.1803029f; private float longitude = 121.4864084f;
图层可以定义N多,只要你能够放下就OK!
在异步线程中初始化好百度地图,initBaiduMap();
/** * 用户poi自定义图 */ class MyPoiOverlay extends PoiOverlay { public MyPoiOverlay(com.baidu.mapapi.map.BaiduMap arg0) { super(arg0); } /** *覆盖物的点击事件 */ @Override public boolean onPoiClick(int arg0) { super.onPoiClick(arg0); PoiInfo poiInfo = getPoiResult().getAllPoi().get(arg0);// 检索poi详细信息 mPoiSearch.searchPoiDetail(new PoiDetailSearchOption().poiUid(poiInfo.uid)); return true; } }
mTrafficOverLay = new MyPoiOverlay(mBaiduMap); mSchoolOverLay = new MyPoiOverlay(mBaiduMap); mLiveOverLay = new MyPoiOverlay(mBaiduMap);
这些初始化工作还是放在initBaiduMap()方法中进行.
搜索方式有一下三种,根据不同的需求来做,这这三个方法都有一个传入参数,page,当我们发起POI搜索时会搜到很多条,而这些搜索结果可以分为N页,每页N条这个page是显示第几页.也可以不用这个参数去掉pageNum(page)这段代码,在图层添加方法中加入mLiveOverLay.zoomToSpan();方法将所有的结果都显示出来.
/** * 城市内搜索 */ private void citySearch(int page) { // 设置检索参数 PoiCitySearchOption citySearchOption = new PoiCitySearchOption(); citySearchOption.city("上海");// 城市 citySearchOption.keyword("KFC");// 关键字 citySearchOption.pageCapacity(15);// 默认每页10条 citySearchOption.pageNum(page);// 分页编号 // 发起检索请求 mPoiSearch.searchInCity(citySearchOption); } /** * 范围检索 */ private void aroundSearch(int page) { PoiBoundSearchOption boundSearchOption = new PoiBoundSearchOption(); LatLng southwest = new LatLng(latitude - 0.01, longitude - 0.012);// 西南 LatLng northeast = new LatLng(latitude + 0.01, longitude + 0.012);// 东北 LatLngBounds bounds = new LatLngBounds.Builder().include(southwest) .include(northeast).build();// 得到一个地理范围对象 boundSearchOption.bound(bounds);// 设置poi检索范围 boundSearchOption.keyword("美食");// 检索关键字 boundSearchOption.pageNum(page); mPoiSearch.searchInBound(boundSearchOption);// 发起poi范围检索请求 } /** * 附近检索 */ private void nearSearch(int page) { PoiNearbySearchOption nearbySearchOption = new PoiNearbySearchOption(); nearbySearchOption.location(new LatLng(latitude, longitude)); nearbySearchOption.keyword("学校"); nearbySearchOption.radius(1000);// 检索半径,单位是米// nearbySearchOption.pageNum(page); mPoiSearch.searchNearby(nearbySearchOption);// 发起附近检索请求 }
我们可以在界面中定义几个Button,比如学校,生活,KFG,银行,交通等,按一个按键显示一种POI搜索结果,多种图层可以同时显示.这个过程就不写出了,都会写的!我们统一写一个在Map中添加图层的方法addOverLay(MyOverLay overLay),放在UI线程中
@UiThread(propagation = UiThread.Propagation.REUSE) void addMyOverLay(PoiResult poiResult) { mLiveOverLay.setData(poiResult);mLiveOverLay.addToMap();// 缩放地图,使所有Overlay都显示 mLiveOverLay.zoomToSpan(); mBaiduMap.setOnMarkerClickListener(mLiveOverLay);//设置覆盖物的点击事件 }
如果搜索成功那将结果添加到图层,如果搜索失败进行提示.
/** * POI检索监听器 */ OnGetPoiSearchResultListener poiSearchListener = new OnGetPoiSearchResultListener() { /** * 搜索完毕后的回调事件,当搜素完毕后可以给与用户提示! */ @Override public void onGetPoiResult(PoiResult poiResult) { if (poiResult.error == SearchResult.ERRORNO.NO_ERROR) {//搜索正常 addMyOverLay(poiResult);//添加图层 } else { Toast.makeText(BaiduMap.this, "chu cuo" + poiResult.error , Toast.LENGTH_LONG).show(); } } /** * 点击一个覆盖物后回调的事件,比如如果点击一个覆盖物后没有该覆盖物的详细信息,在这里可以提示并得到失败 * 的原因 */ @Override public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) { } };
这个类百度的3.0之前和之后有所不同.这个方法也在initBaiduMap()方法中调用
/** * 初始化POI搜索 */ private void checkSearchParam() { if (null == mPoiSearch) { mPoiSearch = PoiSearch.newInstance(); mPoiSearch.setOnGetPoiSearchResultListener(poiSearchListener); } }
当我们按下按键显示一种POI搜索结果.
public void onClick(View v) { switch (v.getId()) { case R.id.map_detail_back_tv:// 返回 this.finish(); break; case R.id.map_live://生活isLiveSelect = !isLiveSelect; nearbySearch(1);break; ..... } }
@Click(R.id.button_clean) void poiClean() { mLiveOverLay.removeFromMap(); }
这样基本上POI搜索就完毕了.不过有种需求比如我们搜索了学校,和KFG两种同时显示,但是百度地图3.0以上的版本搜索结果都是红色汽包这样很难分清楚,而且官方似乎也没有相应的方法提供给我们.这样需要我们自己想办法.我找到了两种方法.
第一种 :代码很简单,但是弊端是没有了POI点击事件的产生了,
我们将添加图层方法改成如下:
@UiThread(propagation = UiThread.Propagation.REUSE) void addMyOverLay(PoiResult poiResult) { mLiveOverLay.setData(poiResult);// mLiveOverLay.addToMap();//如果不注释掉图层上会显示两种气泡重合 List<OverlayOptions> ops = new ArrayList<OverlayOptions>(); List<PoiInfo> pois = poiResult.getAllPoi(); BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.mipmap.ic_location); for(int i = 0;i < pois.size();i++){ OverlayOptions op = new MarkerOptions().position(pois.get(i).location).icon(bitmap); ops.add(op);mBaiduMap.addOverlay(op); } // 缩放地图,使所有Overlay都在合适的视野内 mLiveOverLay.zoomToSpan();mBaiduMap.setOnMarkerClickListener(mLiveOverLay);//加上也没有用 }
第二种 :我们写一个继承OverlayManager的内部类,这个是我在网上找到的一种解决方法,将(private MyPoiOverlay mLiveOverLay;// 生活图层)改为(private MyOverlayManager mLiveOverLay;// 生活图层),下面的初始化相应的改变.去掉数子显示都可以自己进行客制化修改.
/** * 覆盖物 */ class MyOverlayManager extends OverlayManager { private PoiResult poiResult = null; public MyOverlayManager(BaiduMap baiduMap) { super(baiduMap); } public void setData(PoiResult poiResult) { this.poiResult = poiResult; } @Override public boolean onMarkerClick(Marker marker) { if (marker.getExtraInfo() != null) { int index = marker.getExtraInfo().getInt("index"); PoiInfo poi = poiResult.getAllPoi().get(index);// 详情搜索 mPoiSearch.searchPoiDetail((new PoiDetailSearchOption()) .poiUid(poi.uid)); return true; } return false; } @Override public List<OverlayOptions> getOverlayOptions() { if ((this.poiResult == null)|| (this.poiResult.getAllPoi() == null)) return null; ArrayList<OverlayOptions> arrayList = new ArrayList<OverlayOptions>(); for (int i = 1; i < this.poiResult.getAllPoi().size(); i++) { if (this.poiResult.getAllPoi().get(i).location == null)c ontinue;// 给marker加上标签 Bundle bundle = new Bundle(); bundle.putInt("index", i); arrayList.add(new MarkerOptions() .icon(BitmapDescriptorFactory .extraInfo(bundle) .position(this.poiResult.getAllPoi().get(i).location)); } return arrayList; } /** * 往图片添加数字 */ private Bitmap setNumToIcon(int num) { BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(R.mipmap.ic_location); Bitmap bitmap = bd.getBitmap().copy(Bitmap.Config.ARGB_8888, true); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setAntiAlias(true);int widthX;int heightY = 0;if (num < 10) { paint.setTextSize(30); widthX = 8; heightY = 6; } else { paint.setTextSize(20); widthX = 11; } canvas.drawText(String.valueOf(num), ((bitmap.getWidth() / 2) - widthX), ((bitmap.getHeight() / 2) + heightY), paint);return bitmap; } @Override public boolean onPolylineClick(Polyline polyline) { return false; } }
在开发过程中我出现过报错—>PERMISSION_UNFINISHED,查明原因是因为地图初始化没有完成我就去POI搜索了,我们可以将其放在一个点击事件中或者在程序运行延迟几秒再去搜索.
POI开发就完毕了,希望大家能多多指点,有不对或者侵权之处请告知谢谢!